Evolution Programming Resources |
Eine wichtige Erweiterung die mit Windows 95 eingeführt wurde,
sind die sogenannten Tooltips. Es handelt sich dabei um kleine
Beschreibungsfenster, die eingeblendet werden, sobald sich der Mauszeiger
einige Zeit über einem als Tool definierten rechteckigen
Bereich oder Fenster befindet. Durch diese Tooltips wurden die
allgegenwärtigen Werkzeugleisten zum ersten mal auch tatsächlich
benutzbar.
Die meisten Klassenbiblioteken, wie z.B. MFC oder OWL, behandlen das
Anzeigen von Tooltips für Werkzeugleisten selbst. Der Anwender
muß sich nicht um das Tooltip Control kümmern. Will man
jedoch Tooltips in Dialogen oder eigenen Fenstern verwenden, muß
man sich doch mit der Funktionsweise des Tooltip Controls
auseinandersetzen - besonders, da dieses Control einige Macken hat,
die seine Anwendung häufig erschweren.
Wie jedes andere Common Control wird das Tooltip Control durch die
Funktion CreateWindow(Ex) erstellt. Dabei ist als Klassenname TOOLTIP
anzugeben. Die Kommunikation mit dem Control erfolgt nach seiner Erstellung
nur noch über Nachrichten. Jedem Tooltip Control können
über die Nachricht TTM_ADDTOOL Tools hinzugefügt werden.
Ein Tool ist entweder ein ganzes Fenster oder ein rechteckiger
Bereich innerhalb eines Fensters. Jedem Tool kann eine Beschreibung zugeordnet
werden, die angezeigt wird, sobald sich die Maus innerhalb des Tools befindet.
Jedes Tooltip kann beliebig viele Tools verwalten.
Damit das Tooltip Control korrekt arbeiten kann, muß es über
die Mausnachrichten, die das Fenster erreichen, das eine Tool enthält,
informiert werden. Dies geschieht normalerweise, indem man die
eintreffenden Nachrichten durch die TTM_RELAYEVENT Nachricht an das
Tooltip Control weiterleitet. Dadurch kann das Tooltip Control erkennen,
ob sich der Mauszeiger innhalb eines Tools befindet und nach einer kurzen
Wartezeit den Tooltip anzeigen. Dieses Vorgehen funktioniert
natürlich nicht für Dialoge. Die Nachrichtenschleife eines
Dialogs liegt innerhalb von Windows und man hat keine Möglichkeit an
diese Nachrichten zu gelangen und kann sie folglich nicht an das
Tooltip Control weiterleiten. (Es stimmt natürlich nicht ganz, daß
man keine Möglichkeit hätte an diese Nachrichten zu gelangen -
eine davon werde ich nachher sogar demonstieren)
Für diesen Fall haben jedoch die Microsoft Programmierer vorgesorgt:
beim Hinzufügen eines Tools zu einem Tooltip Control kann
das Flag TTF_SUBCLASS angegeben werden. Dies veranlaßt das
Tooltip Control die Fensterprozedur des Fensters, das das Tool
enthält, durch seine eigene zu ersetzen. So kann das Tooltip Control
jede Nachricht abfangen und bearbeiten, bevor sie an die ursprüngliche
Fensterprozedur weitergeleitet wird.
Will man das Tooltip Control in Dialogen oder eigenen Fenster einsetzen,
um die Inhalte von anderen Controls zu kommentieren (z.B. von Editfeldern)
wird man bald auf einen Bug des Tooltip Controls stoßen: zu
statischen Textfeldern (static controls) und deaktivierten (disabled)
Controls kann kein Tooltip angezeigt werden, auch wenn das Control
korrekt als Tool registiert wurde.
Dies liegt daran, daß das Tooltip Control die Funktion
WindowFromPoint() verwendet, um zu ermitteln zu welchem Tool ein
Tooltip angezeigt werden soll.
Erhält ein Tooltip Control eine WM_MOUSEMOVE Nachricht (entweder
über TTM_RELAYEVENT oder über die subgeclasste Fensterprozedur)
ermittelt es über WindowFromPoint das Fenster, das die aktuellen
Mauskoordinaten enthält. Ist dieses Fenster vollständig
als Tool registriert oder befinden sich die Mauskoordinaten noch
zusätzlich in einem rechteckigen Toolbereich, dann wird nach
einem Delay von ca. 0,5 Sekunden der Tooltip anzeigt.
Die Funktion WindowFromPoint arbeitet aber nicht ganz so, wie man
es von ihr erwartet: befinden sich die übergebenen Koordinaten
innerhalb eines statischen Textfeldes oder eines deaktivierten
(disabled) Fensters, dann wird nicht das Fenster selbst, sondern sein
Elternfenster zurückgegeben.
Erhält das Tooltip Control also eine WM_MOUSMOVE Nachricht,
während sich der Cursor über einem statischen Textfeld oder
einem deaktivierten Fenster befindet, dann liefert die Funktion
WindowFromPoint das Elternfenster dieses Fensters und nicht das Fenster
selbst. Das Tooltip Control durchsucht nun vergeblich die Liste seiner
Tools nach diesem Fenster. Folglich wird kein Tooltip angezeigt.
Der Workround ist prinzipell ziemlich einfach, jedoch nicht so einfach zu
implementieren: da die statischen Textfelder und deaktivieren Fenster
für die WindowFromPoint Funktion durchsichtig sind, fügt man
einfach zum Parentfenster ein rechteckiges Tool hinzu, das
genau unter dem Textfeld bzw. deaktivierem Fenster liegt.
Jetzt hat man nur noch das Problem, daß das Fenster zwar für
WindowFromPoint durchsichtig ist, jedoch nicht für die Mausnachrichten
selbst. Sie werden weiterhin an das Fenster gesendet, in dem sich der
Cursor zum Zeitpunkt der Nachichtenversendung befindet - in unserem
Fall also an das statisch Textfeld bzw. das deaktivierte Fenster.
Folglich haben wir bis jetzt nichts gewonnen; der Tooltip wird immer
noch nicht angezeigt, da das Tooltip Control für den rechteckigen
Bereich im Elternfenster überhaupt keine Mausnachrichten erhält.
Um dies zu vermeiden ist ein wenig Aufwand nötig. Die Mausnachrichten
an das statische Textfeld bzw. disabled Control werden abgefangen und
so modifiziert an das Tooltip Control weitergegeben, das sie aussehen wie
Mausnachrichten, die an das Eltenfenster gerichtet sind.
Handelt es sich bei dem Elternfenster jedoch um einen Dialog, so hat
man das Problem, das man wieder nicht an die Nachrichten heran kommt.
Subclassing stellt dabei sicher eine Lösung dar, ich habe mich in
meinem Besipielcode jedoch für einen Messagehook entschieden.
Ich habe eine Klasse TTooltipEx erstellt, die das Problem für den
Benutzer völlig transparent löst. Der Code dieser Klasse
ist weiter unten in diesesm Dokument verfügbar.
Diese Klasse hat ein paar Schwachstellen, die bei den meisten
Anwendungsfällen nicht so ins Gewicht fallen sollten, der
Vollständigkeit halber jedoch angeführt sind.
| ||
|