![]() |
TComboBox - MouseMove
Ich habe in der Main-Form eine TComboBox und möchte auf MouseMove-Events reagieren, wenn sich der Maus-Zeiger in der ComboBox oder in der aufgeklappten Liste befindet.
Meine bisherige Lösung: 1) In einer Unit, die in der Uses-Liste der Main-Form aufgeführt ist habe ich deklariert
Delphi-Quellcode:
2) Im FormCreate der Main-Form habe ich
TComboBox = class(Vcl.StdCtrls.TComboBox)
public property OnMouseMove; end;
Delphi-Quellcode:
und
procedure TMain.FormCreate(Sender: TObject);
begin … ComboBox.OnMouseMove := ComboBoxMouseMove; … end;
Delphi-Quellcode:
wo ich auf das MouseMove reagiere.
procedure TMain.ComboBoxMouseMove(Sender:TObject; Shift:TShiftState; X,Y:Integer);
begin … … end; Das funktioniert gut, allerdings nur, wenn sich der Maus-Zeiger im Textfeld der ComboBox befindet. Ist die Liste aufgeklappt und ich bewege die Maus im aufgeklappten Teil, wird kein MouseMove-Event ausgelöst (jeenfalls kommt es nicht im ComboBoxMouseMove an). Frage: Wie erreiche ich, dass ich auch auf Mausbewegungen im aufgeklappten Bereich der ComboBox reagieren kann. Ein weiteres Problem: Wen die Liste aufgeklappt wird, reicht diese bis an den unteren Rand der Form. Ich möchte aber die Höhe begrenzen. Ich habe es bereits mit DropDownCount versucht, aber das funktioniert nicht, auch dann nicht, wenn ich DropDownCount zur Laufzeit setze. Ich vermute, dass das an Style = csOwnerDrawFixed liegt. Frage: Wie kann ich die Höhe der Liste begrenzen. |
AW: TComboBox - MouseMove
AFAIR ist die DropDownList ein eigenes Fenster. Das müsstest Du dann extra behandeln / overriden.
|
AW: TComboBox - MouseMove
Dort ->
![]()
Delphi-Quellcode:
Auf gleichem Server auch eine Antwort für Mouse Events, les mal ob Dir das reicht, über das Hint-Ereignis.
procedure TCustomCombo.SetDropDownCount(const Value: Integer);
begin if Value <> FDropDownCount then begin FDropDownCount := Value; if HandleAllocated and CheckWin32Version(5, 1) and ThemeServices.ThemesEnabled then SendMessage(Handle, CB_SETMINVISIBLE, WPARAM(FDropDownCount), 0); end; end; ![]() |
AW: TComboBox - MouseMove
Zitat:
SetDropDownCount wird ja aufgerufen, wenn ich zur Laufzeit den DropDownCount setze, aber wie in #1 erwähnt, bringt das nichts. Ich hab dann mal spaßeshalber im Form.Create ein
Delphi-Quellcode:
eingefügt und siehe da, das funktioniert.
SendMessage(ComboBox.Handle, CB_SetMinVisible, 10, 0);
Ist wohl nicht so sehr sauber, aber "sieht ja niemand". Und zum Thema MouseMove hab ich mir mal angeschaut was unter dem von dir gezeigten Link zu finden ist. Im Moment verstehe ich das alles nicht - muss ich mich wohl durchbeißen... |
AW: TComboBox - MouseMove
Hallo Amateurprofi,
Zitat:
Zitat:
|
AW: TComboBox - MouseMove
Liste der Anhänge anzeigen (Anzahl: 2)
Zitat:
Dir von dir gezeigte Methode "TCustomCombo.SetDropDownCount(const Value: Integer);" ist bereits Bestandteil von TCustomCombo und TComboBox ist ein Nachfahre von TCustomCombo. Was also soll das bringen? Ich hab mittlerweile auch geprüft, ob TCustomCombo.SetDropDownCount auch aufgerufen wird, wenn DropDownCount gesetzt wird. Wird sie, aber das "SendMessage" wird nicht ausgeführt (wg. StyleServices). Und was ich genau will? In meinen Programmen ist es Standard, dass am unteren Rand der Form eine Statusbar ist und darüber ist ein freier Bereich, in dem ich zur Laufzeit Hinweise ausgebe. (Schau mal hier ![]() Die Combobox, listet einige Musik-Titel auf und zeigt nicht nur die Titel sondern auch diverse Informationen zu dem jeweiligen Titel (siehe Anhang "Combobox aufgeklappt"). Ich möchte, wenn ich die Maus über die aufgeklappte Liste bewege, im oben erwähnten Hinweis-Feld ausgeben, wofür der Wert steht, auf den die Maus zeigt (siehe Anhang "Combobox zugeklappt"). Das ist aber vergebliche Mühe, wenn die Liste bis zum unteren Rand der Form reicht. Deshalb will ich die Höhe der aufgeklappten Liste begrenzen, so dass das Hinweis-Feld frei bleibt. Klar könnte ich den Hinweis auch direkt beim Cursor einblenden - ich will aber bei meinem Standard-Verfahren bleiben. |
AW: TComboBox - MouseMove
Zitat:
ich habe mir angeschaut, was unter den Links, die Du netterweise zur Verfügung gestellt hast, zu lesen ist. Wenn ich das richtig verstehe, dann funktioniert Dein Vorschlag über das Hint-Event zu gehen, in meinem Fall nicht (Style ist csOwnerDrawFixed, nicht csSimple). Zitat:
Problem ist, dass ich nicht einmal ansatzweise verstehe, wie ich das realisieren kann. Kannst Du mir kurz skizzieren wie ich das machen kann. Was ich mir vorstelle ist: Wenn die Liste aufgeklappt ist, und die Maus in der List bewegt wird, wird ein MouseMove ausgelöst und eine "eigene" MouseMove Methode ausgerufen, in der ich die die Position der Maus auswerten kann. Vielen Dank. |
AW: TComboBox - MouseMove
Ich gebe Dir ein Beispiel okay, da ich Deinen Source nicht kenne ist es universal Einsetzbar.
Delphi-Quellcode:
type
TForm1 = class(TForm) ComboBox1: TComboBox; Label1: TLabel; procedure FormCreate(Sender: TObject); private procedure ApplicationIdle(sender: TObject; var Done: boolean); end;
Delphi-Quellcode:
procedure TForm1.ApplicationIdle(sender: TObject; var Done: boolean);
var pt: TPoint; wnd: HWND; buf: array[0..128] of Char; i: Integer; begin GetCursorPos(pt); wnd := WindowFromPoint(pt); If wnd <> 0 then begin buf[0] := #0; GetClassName(wnd, buf, SizeOf(buf)); If StrIComp(buf, 'ComboLBox') = 0 Then Begin Windows.ScreenToClient(wnd, pt); i := SendMessage(wnd, LB_ITEMFROMPOINT, 0, lparam(PointToSmallpoint(pt))); If i >= 0 Then Begin SendMessage(wnd, LB_GETTEXT, i, integer(@buf)); Label1.Caption := buf; // <<<< HIER ÄNDERE DEN EMPFÄNGER, MIR IST DEIN SOURCE UNBEKANNT Exit; End; End; end; end;
Delphi-Quellcode:
Dieser Code bewirkt das mir im Label1 ein Item aus einer aufgeklappten ComboBox wo Maus gerade drüber ist angezeigt wird.
procedure TForm1.FormCreate(Sender: TObject);
begin ComboBox1.DropDownCount := 2; Application.OnIdle := ApplicationIdle; end; Ob Du nun den Item Text darstellst oder per Pos() nach irgend was suchst um den Output anzupassen obliegt Deiner Phantasie. Löst das Dein Problem oder habe ich es falsch verstanden? Ps: Getestet mit D2009, da reicht es mit dem DropDownCount zu arbeiten. |
AW: TComboBox - MouseMove
Alternativ kannst Du natürlich auch Label1.Caption := buf; mit einer Funktion/Procedure ersetzen was Dir den Output vorbereitet und irgendwo hin sendet.
So umgehst Du zumindest die SubClass / CustomCombo etc Problematik. Über der Zeile GetClassName(wnd, buf, SizeOf(buf)); könntest Du die Abfrage auch noch vertiefen/konkretisieren (wnd := WindowFromPoint(pt); mit einem bestimmten Control Handle einer ComboBox zum Beispiel), in dieser gezeigten Variante greift ApplicationIdle auf alle aufgeklappten ComboBox Listen Einträge zu und gibt Inhalt unter Maus weiter. Ps: Da ich es über OnIdle Event laufen lasse, kann es passieren das wenn Deine Applikation gerade schwer am schuften ist Du kein Event gefeuert bekommst um das Item unter Maus auszuwerten. |
AW: TComboBox - MouseMove
Zitat:
vielen Dank. Nach ein paar Anlaufschwierigkeiten funktioniert das hervorragend. Eine Beobachtung am Rande: Wenn die Liste aufgeklappt wird und die Maus in das TextFeld der ComboBox gestellt wird, liefert GetClassName nicht 'ComboLBox'. Ist auch logisch, denn die Maus ist ja nicht in der Liste. Bewege ich aber nach dem Aufklappen die Maus in die Liste und dann in das TextFeld, dann liefert GetClassName 'ComboLBox', auch wenn die Maus nicht mehr in der Liste ist. Hierbei ist es egal, ob ich die Maus in der Liste einfach nach oben bis in das Textfeld verschiebe oder z.B. nach rechts aus der Liste heraus, außerhalb der Liste nach oben und dann in das Textfeld. Der mit
Delphi-Quellcode:
geholte Index ist dann (65536 + Index der gerade markierten Zeile).
I:=SendMessage(Wnd,LB_ITEMFROMPOINT,0,LParam(PointToSmallpoint(MP)));
Da das zu Problemen führte hab ich in ApplicationIdle zunächst abgefragt, ob Wnd=ComboBox.Handle ist (also die Maus ins TextFeld zeigt) und dann mit ComboBox.ItemIndex weitergemacht. Überraschung hierbei: Combobox.ItemIndex ist dann der Index des in der Liste gerade markierten Eintrags, nicht des Eintags, der im Textfeld angezeigt wird. Das hab ich gelöst, indem ich im ComboBoxDropDown den ItemIndex der Combobox in "fComboBoxIndex" speichere. Bei mir sieht das jetzt so aus:
Delphi-Quellcode:
procedure TMain.cbMelodiesDropDown(Sender: TObject);
begin fComboBoxIndex:=cbMelodies.ItemIndex; Application.OnIdle:=ApplicationIdle; end;
Delphi-Quellcode:
procedure TMain.cbMelodiesCloseUp(Sender: TObject);
begin Application.OnIdle:=Nil; end;
Delphi-Quellcode:
"TSI" ist ein Array das Zeiger auf die Daten der in der Combobox gezeigten Melodien enthält.
PROCEDURE TMain.ApplicationIdle(Sender:TObject; var Done:Boolean);
const CN='ComboLBox'; var I:Integer; MP:TPoint; Wnd:HWND; Buf:array[0..Length(CN)] of Char; begin GetCursorPos(MP); EraseHint; Wnd:=WindowFromPoint(MP); if Wnd<>0 then if Wnd=cbMelodies.Handle then begin WinApi.Windows.ScreenToClient(Wnd,MP); if ComboBoxIndex>0 then ShowComboBoxHint(ComboBoxIndex,MP.X); end else if GetClassName(Wnd,Buf,SizeOf(Buf)+1)=Length(CN) then begin if StrIComp(Buf,CN)=0 then begin WinApi.Windows.ScreenToClient(Wnd, MP); I:=SendMessage(Wnd,LB_ITEMFROMPOINT,0,LParam(PointToSmallpoint(MP))); if InRange(I,0,High(TSI)) then ShowComboBoxHint(I,MP.X); end; end; end; Hintergrund dieser Konstruktion ist, dass ich die in der Combobox-Liste gezeigten Einträge nach beliebigen Kriterien sortiert anzeigen kann. Im ComBoxBox DrawItem greife ich auf TSI[] zurück, nicht auf Combobox.Items (das nur leere Strings enthält).
Delphi-Quellcode:
// Daten einer Melodie
TTrackDataRec=packed Record Index:Integer; // Nummer des Tracks Name:String; // Name des Tracks Time:Integer; // Spieldauer des Tracks in ms SequenceCount:Integer; // Anzahl Sequenzen im Track Count:Integer; // Wie viel Töne Track gespielt werden ToneCount:Byte; // Wie viel veschiedene Töne im Track vorkommen MinTone:Byte; // Niedrigster Ton MaxTone:Byte; // Höchster Ton AvgTone:Byte; // Durchschnittlicher Ton MinIntensity:Byte; // Niedrigste Intensity MaxIntensity:Byte; // Höchste Intensity AvgIntensity:Byte; // Durchschnittliche Intensity MinToneCount:Byte; // Niedrigste Anzahl Töne in einer Sequenz MaxToneCount:Byte; // Höchste Anzahl Töne in einer Sequenz AvgToneCount:Byte; // Durchschnittliche Anzahl Töne in einer Sequenz MinSequenceTime:Integer; // Spieldauer der kürzesten Sequenz MaxSequenceTime:Integer; // Spieldauer der längsten Sequenz AvgSequenceTime:Integer; // Durchschnittliche Spieldauer der Sequenzen ColorRange:TColorRange; // Zugeordneter Farbbereich end; TPTrackDataRec=^TTrackDataRec; TTrackData=Array of TTrackDataRec; TTrackDataSortIndex=Array of TPTrackDataRec; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:58 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz