| Autor |
Beitrag |
Stefan S.
      
Beiträge: 184
D5
|
Verfasst: Fr 05.01.07 21:11
Hallo allerseits,
Ich habe in einem Programm Buttons mit Highlight-Effekt, d.h. ihre Farbe ändert sich, wenn man den Mauszeiger auf sie bewegt. Das mach ich ganz simpel mit OnMouseMove, nämlich hab ich den Befehl, der die Farbe ändert, beim OnMouseMove des jeweiligen Buttons und den Befehl, der sie zurücksetzt beim OnMouseMove von allen anderen Buttons und auch ganz anderen Objekten (wie z.B. der Form selber).
Damit ist es aber noch nicht getan, denn wenn man den Cursor sehr schnell an eine Stelle außerhalb des Formulars bewegt, bleibt das Highlight erhalten. Ich muss also auch abfragen, ob sich der Cursor außerhalb der Form befindet und in diesem Falle die Farbe zurücksetzen. Und da ist mein Problem: Wo bring ich diese Abfrage unter? In meiner Unerfahrenheit habe ich bisher einfach immer einen Timer mit Intervall '1' platziert, der quasi 1000 mal pro Sekunde abfrägt, ob der Cursor außerhalb der Form ist und das ganze funktioniert natürlich, aber diese Methode ist doch wohl sehr unschön und unprofessionell, schon allein, weil der Timer ja ständig Rechenleistung verbraucht (wenn auch bei den heutigen Systemen ein Timer mit einer Abfrage wahrscheinlich kaum was ausmacht).
Wo bringe ich die Abfrage am besten unter? In einer Prozedur, die ständig wiederholt ausgeführt wird? Oder gibt es ein Ereignis, das sich dafür eignet? Gibt es überhaupt einen besseren Weg, so ein Button-Highlight umzusetzen?
MfG,
Stefan
|
|
Jakob Schöttl
      
Beiträge: 929
Erhaltene Danke: 1
Delphi 7 Professional
|
Verfasst: Sa 06.01.07 01:07
Also, da gibts glaub ich was viel besseres als OnMouseMove!
Application.OnHint ist ein Ereignis, das sofort dann auftritt, wenn der Benutzer auf eine Komponente zeigt mit der Maus...
Wenn der Auslöser von OnHint = Form1, dann kannst du die Farbe des Buttons zurücksetzen, und wenn der Auslöser Button1 ist, dann kannst du die Farbe setzen.
Nimm dazu ein Objekt der Klasse TApplicationEvent.
|
|
Stefan S. 
      
Beiträge: 184
D5
|
Verfasst: Sa 06.01.07 01:15
Ähm, mal blöd gefragt - was ist daran jetzt besser als an OnMouseMove? Einfacher wird es dadurch nicht und eigentlich ist OnHint für einen anderen Zweck gedacht:
| Zitat: | | Mit einer OnHint-Ereignisbehandlungsroutine können Sie Aktionen programmieren, die eingeleitet werden, wenn sich der Mauszeiger über einem Steuerelement befindet, dessen Eigenschaft Hint keinen Leerstring enthält. |
Geholfen wäre mir zum Beispiel, wenn es für den Button ein Ereignis gäbe, was eintritt, wenn der Mauszeiger nicht auf ihn zeigt, dann könnte ich mir die Abfrage der Mauskoordinaten sparen. Aber sieht nicht so aus, als gäbe es so etwas.
Wie auch immer, es würde mich so oder so mal interessieren, wo man so eine Abfrage, die im Prinzip ständig wiederholt durchgeführt werden soll, am besten unterbringt.
|
|
Jakob Schöttl
      
Beiträge: 929
Erhaltene Danke: 1
Delphi 7 Professional
|
Verfasst: Sa 06.01.07 01:21
Eben! die ständige Abfrage kannst du dir sparen, wennd u OnHint nimmst! Wenn der Mauszeiger zum ersten mal wieder auf den Button zeigt, dann kannst du die Farbe ändern. Wenn er danach zum ersten mal wieder aufs Form zeigt, dann kannst du sie wieder auf leer ändern!
Das ist der Vorteil an onHint: das Ereignis wird nicht bei der Mausbewegung ausgelöst, sondern einmalig eben dann, wenn der Cursor auf das Steuerelement fährt.
und so viel ich weiß, wird es auch ausgelöst, wenn der Hint = '' ist. und es wird nicht verzögert ausgelöst, so wie der hint auch verzögert angezeigt wird...
|
|
wulfskin
      
Beiträge: 1349
Erhaltene Danke: 1
Win XP
D5 Pers (SSL), D2005 Pro, C, C#
|
Verfasst: Sa 06.01.07 01:27
Hallo,
für diesen Zweck gibt es die beiden "Nachrichten" CM_MOUSEENTER und CM_MOUSELEAVE. Allerdings finde ich dazu nichts mehr in der API-Dokumentation, aber ich denke die gibt es immer noch.
Ein Beispiel findet man bei den Schweizern!
Gute Nacht,
Hape
_________________ Manche antworten um ihren Beitragszähler zu erhöhen, andere um zu Helfen.
|
|
jaenicke
      
Beiträge: 19341
Erhaltene Danke: 1752
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 06.01.07 01:50
Ja, die gibt es noch... Und es gibt sogar OnMouseLeave beim Formular.
Das wird, wie der Name schon sagt, ausgelöst, wenn die Maus das Formular verlässt.
Bei extrem schnellen Mausbewegungen oder langsamen PCs wird es aber u.U. anscheinend nicht ausgelöst bzw. die Botschaften nicht gesendet. Oder die Anwendung verarbeitet die nicht korrekt.
Dieses Problem konnte man ja auch an der Delphi 7 IDE beobachten. Wenn man da schnell mit der Maus über die ToolButtons gegangen ist, dann blieben die aktiviert. Allerdings nur bei etwas langsameren PCs. (Oder war es nicht Delphi 7 sondern eine andere Version? Egal...)
|
|
Jakob Schöttl
      
Beiträge: 929
Erhaltene Danke: 1
Delphi 7 Professional
|
Verfasst: Sa 06.01.07 13:38
wulfskin hat folgendes geschrieben: | Hallo,
für diesen Zweck gibt es die beiden "Nachrichten" CM_MOUSEENTER und CM_MOUSELEAVE. Allerdings finde ich dazu nichts mehr in der API-Dokumentation, aber ich denke die gibt es immer noch.
Ein Beispiel findet man bei den Schweizern!
Gute Nacht,
Hape |
Aber da müsste man ja für jeden Hightlight-Button eine Klasse ableiten THighlightButton, weil wo soll man sonst die Nachrichten behandeln?
|
|
jaenicke
      
Beiträge: 19341
Erhaltene Danke: 1752
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 06.01.07 13:42
CM_MOUSEENTER und CM_MOUSELEAVE sind doch schon eingebaut...
In OnMouseEnter und OnMouseLeave.
(Delphi 2006)
// EDIT: Ich seh grad, bei Delphi 7 und früher nicht.
Ja, da muss man dann eine abgeleitete Klasse erstellen...
// EDIT2:
Jakob Schöttl hat folgendes geschrieben: | | Aber da müsste man ja für jeden Hightlight-Button eine Klasse ableiten THighlightButton, weil wo soll man sonst die Nachrichten behandeln? |
Wie für jeden? Einmal reicht ja.
|
|
Jakob Schöttl
      
Beiträge: 929
Erhaltene Danke: 1
Delphi 7 Professional
|
Verfasst: Sa 06.01.07 14:12
jaenicke hat folgendes geschrieben: | Jakob Schöttl hat folgendes geschrieben: | | Aber da müsste man ja für jeden Hightlight-Button eine Klasse ableiten THighlightButton, weil wo soll man sonst die Nachrichten behandeln? |
Wie für jeden? Einmal reicht ja. |
Ja, klar reicht einmal, hab mich schlecht ausgedrückt!
|
|
Stefan S. 
      
Beiträge: 184
D5
|
Verfasst: Sa 06.01.07 16:31
jaenicke hat folgendes geschrieben: | Ja, die gibt es noch... Und es gibt sogar OnMouseLeave beim Formular.  |
Ich arbeite mit Delphi 5 und da gibt es kein "OnMouseLeave". Aber wenn es da bei langsameren PCs zu Ungenauigkeiten kommt, ist das eh nix für mich.
@jaenicke: Ehrlich gesagt versteh ich da rein gar nichts. Wenn ich den Code aus dem Beispiel einfach in ein neues Beispielprojekt kopiere, wird mir gemeldet, dass die Deklaration von Form1 fehlt. Zu CM_MOUSEENTER und CM_MOUSELEAVE hab ich weder in der Delphi Hilfe noch bei Windows SDK etwas gefunden. Könntest du es mal genauer erklären oder einen entsprechenden Code posten?
|
|
wulfskin
      
Beiträge: 1349
Erhaltene Danke: 1
Win XP
D5 Pers (SSL), D2005 Pro, C, C#
|
Verfasst: Sa 06.01.07 16:32
Hallo,
was spricht denn dagegen, dass Beispiel bei den Schweizern einfach einmal auszuprobieren?
Gruß Hape!
_________________ Manche antworten um ihren Beitragszähler zu erhöhen, andere um zu Helfen.
|
|
Lannes
      
Beiträge: 2352
Erhaltene Danke: 4
Win XP, 95, 3.11, IE6
D3 Prof, D4 Standard, D2005 PE, TurboDelphi, Lazarus, D2010
|
Verfasst: Sa 06.01.07 16:41
Hallo,
man muss nicht unbedingt eine Klasse ableiten,
hier mal ein Beispiel mit mehreren Labels, funktioniert auch mit D3.
Zum Testen, ein paar Labels auf die Form setzen und den Code übernehmen:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51:
| unit Unit1;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, ComCtrls; type TCMMOUSEENTER = record Msg : Cardinal; Unused : Integer; Sender : TControl; Result : Longint; end; TCMMOUSELEAVE = TCMMOUSEENTER; type TForm1 = class(TForm) Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; private public Procedure MouseEnter(Var Msg: TCMMOUSEENTER); message CM_MOUSEENTER; Procedure MouseLeave(Var Msg: TCMMOUSELEAVE); message CM_MOUSELEAVE; end;
var Form1: TForm1;
implementation
{$R *.DFM} procedure TForm1.MouseEnter(var Msg: TCMMOUSEENTER); begin if ((Msg.Sender) is TLabel) then TLabel(Msg.Sender).Color := clRed; end;
procedure TForm1.MouseLeave(var Msg: TCMMOUSELEAVE); begin if ((Msg.Sender) is TLabel) then TLabel(Msg.Sender).Color := clBtnFace; end;
end. |
_________________ MfG Lannes
(Nichts ist nicht Nichts) and ('' <> nil ) and (Pointer('') = nil ) and (@('') <> nil )
|
|
Stefan S. 
      
Beiträge: 184
D5
|
Verfasst: Sa 06.01.07 16:41
@wulfskin: OK, jetzt hab ichs geschnallt. ^^ Komponente installiert, funktioniert wunderbar.
@Lannes: Das gefällt mir fast noch besser, wenn ich ohne abgeleitete Klasse auskomme. Werde mir den Code später nochmal genauer ansehen, aber funktionieren tut es auf jeden Fall.
|
|
Stefan S. 
      
Beiträge: 184
D5
|
Verfasst: So 07.01.07 15:16
(Sorry wegen Doppelpost, aber es gibt ja Neuigkeiten)
Also ein Nachteil ist mir bei dieser Methode dann doch aufgefallen: Der Highlight-Effekt wird auf alle Komponenten dieses Typs (in diesem Fall TLabel) angewendet und damit auch auf welche, die eigentlich kein Highlight haben sollen oder z.B. eine andere Farbe. Da müsste ich dann noch den Controls-Wert abfragen, um festzustellen, ob die jeweilige Komponente ein Highlight hat oder nicht, oder?
Um nochmal auf meine ursprüngliche Methode mit OnMouseMove zurückzukommen: Kann man nicht einfach die Abfrage, wo sich der Mauscursor befindet, mit einner sinnvolleren Programmierweise unterbringen (statt dem Timer)? Denn in einem der Formulare des Projektes muss ich auch wegen etwas anderem die Mauskoordinaten ständig abfragen, da hab ich dann das selbe Problem. Auch kann man ja, wenn man das ganze Userinterface nicht mit Komponenten macht sondern Buttons und Texte z.B. in eine Paintbox zeichnet, auch nicht mit OnMouseMove oder CM_MOUSEENTER arbeiten und dann muss es ja auch irgendwie anders gehen.
|
|
wulfskin
      
Beiträge: 1349
Erhaltene Danke: 1
Win XP
D5 Pers (SSL), D2005 Pro, C, C#
|
Verfasst: So 07.01.07 15:35
Hallo Stefan,
zu deinem ersten Absatz: NEIN! Wenn du diese Ereignisse selber implementierst, dann kannst du doch auch selber festlegen, bei welchen Komponenten das Eregnis existiert und bei welchen nicht.
Wenn du das ohne Ableiten einer Komponente machst, dann könnte das natürlich etwas "komplizierter" werden, da du dann ja kein Ereignis implementierst, sondern nur die Methode aufrufst und die Komponente übergibst. In diesem Fall könnte man zum Beispiel die Eigenschaft Tag verwenden um dies zu steuern.
Zum zweiten Absatz: Diese Methode (OnMouseEnter, OnMouseLeave) ist einfach die beste. Nimm diese, oder lass es. Dieses geschustere mit OnMouseMove ist einfach nicht das wahre. Genau für diesen Zweck gibt es ja genau diese Nachrichten!
Wenn du das ganze in eine Paintbox zeichnest, dann musst du natürlich auf OnMouseMove reagieren und überprüfen ob sich die Maus oberhalb eines Unterobjekts befindet, dann sendet aber die PaintBox wieder diese Nachrichten an die jeweiligen Unterobjekte.
Gruß Hape!
_________________ Manche antworten um ihren Beitragszähler zu erhöhen, andere um zu Helfen.
|
|
Stefan S. 
      
Beiträge: 184
D5
|
Verfasst: So 07.01.07 15:54
wulfskin hat folgendes geschrieben: | | zu deinem ersten Absatz: NEIN! Wenn du diese Ereignisse selber implementierst, dann kannst du doch auch selber festlegen, bei welchen Komponenten das Eregnis existiert und bei welchen nicht. |
Ich hab mich da jetzt auf Lannes' Code bezogen, also auf die Methode ohne Ableiten einer Komponente.
wulfskin hat folgendes geschrieben: | | Wenn du das ohne Ableiten einer Komponente machst, dann könnte das natürlich etwas "komplizierter" werden, da du dann ja kein Ereignis implementierst, sondern nur die Methode aufrufst und die Komponente übergibst. In diesem Fall könnte man zum Beispiel die Eigenschaft Tag verwenden um dies zu steuern. |
Das mit "Tag" ist eine gute Idee, hab ich auch gleich mal ausprobiert. Also sofern diese Methode nicht irgendwelche Nachteile hat, mach ich das jetzt so, wie Lannes es beschrieben hat, das ist relativ simpel und funktioniert einwandfrei.
|
|
wulfskin
      
Beiträge: 1349
Erhaltene Danke: 1
Win XP
D5 Pers (SSL), D2005 Pro, C, C#
|
Verfasst: So 07.01.07 16:01
Stefan S. hat folgendes geschrieben: | | Das mit "Tag" ist eine gute Idee, hab ich auch gleich mal ausprobiert. Also sofern diese Methode nicht irgendwelche Nachteile hat, mach ich das jetzt so, wie Lannes es beschrieben hat, das ist relativ simpel und funktioniert einwandfrei. |
Nachteile fallen mir spontan nicht ein. Gerade für solche Dinge ist so eine Eigenschaft Tag eigentlich auch gedacht. Wenn du mehrere Dinge im Tag speichern möchtest, kannst du ja immer noch OR-Verknüpfungen auf Konstanten (2er-Potenzen) benutzen.
Viele Grüße,
Hape
_________________ Manche antworten um ihren Beitragszähler zu erhöhen, andere um zu Helfen.
|
|
|