Komponente verliert Focus

Rund um die LCL und andere Komponenten
Antworten
siro
Beiträge: 731
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Komponente verliert Focus

Beitrag von siro »

Hallo,

Ich habe ein Miniproblem mit der Funktionalität OnMouseMove:
Das ist kein Fehler oder Ähnliches, das ist bei Delphi 6 auch so, ich benötige es jedoch etwas anders:

Wenn die linke Maustaste gedrückt ist, wird IMMER OnMouseMove beim Bewegen der Maus aufgerufen,
auch wenn ich den Clientbereich der Komponente verlasse.

Wenn ich die rechte Maustaste drücke, wird OnMOuseMove NUR aufgerufen,
wenn ich mich innerhalb des Clientbereichs bewege.

Die Frage: Wie kann ich das ändern, dass auch bei mbRight IMMER MouseMove aufgerufen wird,
auch wenn ich mich außerhalb des Clientbereichs befinde.


Ich habe schon die Methode
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
überschrieben

und die Message abgefangen:
procedure WMMouseMove(var Message:TLMMouseMove); message LM_MOUSEMOVE;

aber das hilft leider nicht.

-------------------------

Zum Testen einfach ein Panel aufs Formular setzen und bei Ereignisse vom Panel auf OnMouseMove doppelt klicken un den Code eingeben:

Code: Alles auswählen

procedure TForm1.Panel1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  caption:=IntToStr(x);
end;     
 


Programm starten:

Mauscursor ins Panel bewegen. linke Maustaste drücken und festhalten.
Wird nun die Maus, bei gedrückter linker Taste bewegt, erscheint die X-Korodinate in der Beschriftung des Formulars.
Hier funktioniert es auch wenn ich mit der Maus den Bereich des Panels verlasse.

Nun das Gleich mit der rechten Maustaste.
Erst wieder mit der Maus ins Panel, dann rechte Maustaste drücken und festhalten.
Bewege ich die Maus, bei gedrückter rechten Taste, außerhalb des Panels, wird kein MouseMove mehr aufgerufen.
Die x Koordinate wird nicht mehr angezeigt. (L E I D E R :-)


Siro
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

siro
Beiträge: 731
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Komponente verliert Focus

Beitrag von siro »

Guten Abend,
ich habe nun sehr viel rumprobiert, bin aber leider noch zu keinem Ergebnis gekommen.
Habe in meiner Komponente die folgende Message abgefangen und mit einem Beep belegt.

Code: Alles auswählen

procedure AnyMessage(var Message: TLMessage); message CM_MOUSELEAVE;
 
procedure THorScale.AnyMessage(var Message: TLMessage);
begin
  beep;
end;


Tatsächlich wird die Methode aufgerufenn, aber nur wenn ich die rechte Maustaste gedrückt halte
und die Maus aus dem Clientbereich der Komponente bewege. Beim Festhalten der linken Maustaste
wird sie nicht aufgerufen.

Die Komponente verliert den Focus und bekommt ihn wieder wenn die Maus in den Clientbereich bewegt wird.

Wer dafür zuständig ist, konnte ich aber noch nicht ermitteln.


Vielleicht hat ja jemand eine Idee von Euch.
Siro
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: Komponente verliert Focus

Beitrag von Michl »

Darf man fragen wozu?

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

siro
Beiträge: 731
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Komponente verliert Focus

Beitrag von siro »

Klar darf man fragen:

Meine Skalierung für mein Kurvenfenster soll mit festhalten der linken Maustaste komplett verschoben werden
und mit der rechten Maustaste soll nur eine Seite des Scales, entweder nur links, oder nur rechts verändert werden.
Das funktioniert auch soweit, doch wenn ich die Maus verschiebe, lande ich unweigerlich irgendwann
ausserhalb der Komponente. Das kann man sicher auch anders machen, aber ich finde es von der Bedienung her so angenehm.

Beispiel:
Scale (sichtbarer Ausschnitt) hat den Bereich von 20 bis 120
nun schiebe ich mit der linken festgehaltenen Maustaste den Scale auf den Bereich 10 bis 110
oder anderes herum nach 50 bis 150 Es wird also lediglich der sichtbare Ausschnitt verschoben wie ein Scrollbalken.

Wenn ich die rechte Maustaste festhalte und mich links der Skalierung befinde,
schiebe ich lediglich den linken Bereich also von ursprünglich 20 bis 120 zu 10 bis 120 oder 80 bis 120 usw.
Befinde ich mich mit der Maus rechts auf meinem Scale schiebe ich nur den rechten Bereich
also von 20 bis 120 nach 20 bis 50 oder 20 bis 150 usw.
Mit der rechten Maustaste verändere ich also den Zoom.
So kann ich den sichtbaren Ausschnitt meines Kurvenfenster komfortabel anpassen.

Macht sich auch supi für die vertikale Skalierung der Kurven.
Mit der linken Maustaste schiebe ich die komplette Kurve hoch und runter, wie bei einem Oszilloskop
Mit der rechten Maustaste schieben ich nur entweder den oberen oder unteren Bereich der Kurve, skaliere also neu.
Hier kann man das nochmal sehen:
https://www.dropbox.com/s/418rlycvawnej ... 8.mp4?dl=0

Ich versteh nur nicht den Sinn, warum bei gehaltener rechten Maustaste der Focus verloren geht.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: Komponente verliert Focus

Beitrag von Michl »

Das einfachste wäre wahrscheinlich statt der rechten Maustaste z.B. <Ctrl> + linke Maustaste zu verwenden. Auch scheint diese Feature ein Feature von Windows zu sein, da GTK2 und QT4 bei beiden Maustasten identisch reagieren (wie linke Maustaste unter Windows).

Für Windows wäre ein Mousehook eine Möglichkeit https://stackoverflow.com/questions/13345655/how-can-a-control-receive-mouse-events-after-the-mouse-is-dragged-beyond-its-bor. Man könnte auch die Application WindProc abfangen und WM_MOUSEMOVE abfangen http://wiki.lazarus.freepascal.org/Win32/64_Interface#Processing_non-user_messages_in_your_window.

Per LCL fällt mir nur ein, sämtliche OnMouseMove Ereignisse abzufangen und auszuwerten (ein schneller Test geht hier):

Code: Alles auswählen

procedure TForm1.Panel1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  FEnableMouseMove := True;
end;
 
procedure TForm1.MyMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
  MP: TPoint;
begin
  if not FEnableMouseMove then Exit;
  if Shift * [ssRight, ssLeft] = [] then
  begin
    FEnableMouseMove := False;
    Exit;
  end;
  if not (Sender is TControl) then Exit;
 
  MP := TControl(Sender).ClientToScreen(Point(X, Y));
  MP := Panel1.ScreenToClient(MP);
 
  Caption := IntToStr(MP.X);
end;
 
procedure TForm1.ActivateMyMouseMove(aControl: TControl);
var
  i: Integer;
begin
  with aControl do
    OnMouseMove := @MyMouseMove;
  if aControl is TWinControl then
    for i := 0 to TWinControl(aControl).ControlCount - 1 do
      ActivateMyMouseMove(TWinControl(aControl).Controls[i]);
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  ActivateMyMouseMove(Self);
end

Testprojekt anbei. Ob der Aufwand lohnt weiß ich nicht.
Dateianhänge
test.zip
(2.23 KiB) 44-mal heruntergeladen

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

wp_xyz
Beiträge: 4885
Registriert: Fr 8. Apr 2011, 09:01

Re: Komponente verliert Focus

Beitrag von wp_xyz »

Bei TAChart können die ChartTools mit der rechten Maustaste über das Fenster hinausziehen. Vielleicht findest du dort, wie das gemacht ist (Code ist nicht von mir, sonst würde ich es erklären). Suche in den Units TAGraph und TATools nach "tool"

siro
Beiträge: 731
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Komponente verliert Focus

Beitrag von siro »

Guten Morgen,

erst einmal vielen Dank Michl, dass Du Dich mit meinem Problem so intensiv beschäftigt hast.
Das es so problematisch ist, habe ich jetzt nicht erwartet. Ich dachte nur eben mal eine Funktion aufrufen
oder ein Flag setzte und fertig.

Aber es sind sehr wertvolle Informationen dabei (auch die LINKs), unter anderem die Vorgehensweise deines rekursiven abklapperns
der Komponenten in deinem Code. Gefällt mir sehr gut.

Die Zeile:
if Shift * [ssRight, ssLeft] = [] then ....
habe ich noch nicht verstanden, diesen Syntax kenne ich garnicht.
Das soll aber nicht Gegenstand dieses Threads werden.

Auch gut zu wissen, daß diese Funktionalität wohl nur Windows spezifisch ist.

Mit dem zusätzlichen drücken einer Taste hatte ich auch schon in Erwägung gezogen,
zumal ich so diverse Varianten benutzen könnte mit CTRL SHIFT usw.
Ich denke mal, das ist wohl die bessere Lösung, ich wollte ja keine Wissenschaft daraus machen,
habe aber trotzdem noch bischen rumprobiert mit den Messages und die WndProc umgeleitet.

+ bedeutet Message wurde ausgelöst, - Message nicht erkannt:

+ CM_MOUSELEAVE beim verlassen des Clientbereichs bei rechter gedrückter Maustaste
+ CM_MOUSEENTER beim Wiedereintritt in den Clientbereich bei rechter gedrückter Maustaste
- CM_EXIT
- CM_LOSTFOCUS nanu ???
- CM_FOCUSCHANGED nanu ???
- LM_NCMOUSEMOVE
+ LM_CAPTURECHANGED wird nur beim loslassen der LINKEN Maustaste gesendet
- LM_LEAVE
- LM_KILLFOCUS-
- MOUSE_LEAVE
- MOUSE_ENTER

(Msg.msg >= LM_MOUSEFIRST) and (Msg.msg <= LM_MOUSELAST) kommt niemals bei gedrückter rechter Maustaste

Ist schon ein merkwürdiges Verhalten bei Windows.

@wp_xyz:
Auch hier wieder ein Danke, ich werd mal in den Code von TAChart reingucken, ob ich dort noch Informationen finde.

Ich denke mal, das war es zunächst für dieses Problem.

Siro dankt...
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

wp_xyz
Beiträge: 4885
Registriert: Fr 8. Apr 2011, 09:01

Re: Komponente verliert Focus

Beitrag von wp_xyz »

siro hat geschrieben:Die Zeile:
if Shift * [ssRight, ssLeft] = [] then ....
habe ich noch nicht verstanden, diesen Syntax kenne ich garnicht.

Der Operator * bildet bei Mengen die Schnittmenge. Die Zeile heißt dann ausgedeutscht: "Wenn die Schnittmenge zwischen Shift und der Menge bestehend aus ssRight und ssLeft leer ist, dann.." oder - weniger mathematisch - "Wenn weder ssRight noch ssLeft in Shift enthalten sind, dann..." Man prüft also, ob mehrere Elemente in einer Menge enthalten sind, ein "mehrfaches in", sozusagen. Eine längere Schreibweise wäre:

Code: Alles auswählen

if (not ssRight in Shift) and (not ssLeft in Shift) then...

Manchmal findet man auch

Code: Alles auswählen

if Shift * [ssRight, ssLeft] = [ssLeft] then...

Das heißt dann: "Wenn ssLeft in Shift enthalten ist, aber ssRight nicht, dann..."

siro
Beiträge: 731
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Komponente verliert Focus

Beitrag von siro »

Achso, das habe ich jetzt verstanden, so habe ich das noch nie gesehen, hatte bisher immer die längere Variante.

Code: Alles auswählen

if (not ssRight in Shift) and (not ssLeft in Shift) then...


Supi Info: Danke Dir.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Antworten