Visual Basic - Technik, FAQ, Tricks, Beispiele

Home / System / Maus u. Kbd. / Over

Feststellen, ob der Mauszeiger ein Control verläßt

Problem

Bei grafisch anspruchvollen Benutzer-Oberflächen hat man oft das Problem zuverlässig bestimmen zu müssen, ob der Mauscursor ein Control gerade betreten oder - was weit schwieriger festzustellen ist - gerade verlassen hat. Dies wird z.B. bei der Reproduktion des beliebten Hover-Effekts (ein optischer Feedback) benötigt oder bei der Aktualisierung der Statuszeile (als Kontext-sensitive ToolTips-Ergänzung bzw. Kurz-Hilfe).

Als ersten Lösungs-Ansatz wird man sicher auf das MouseMove-Ereignis zurückgreifen wollen, welches immer dann ausgelöst wird, wenn die Maus über ein Control fährt. Doch wie soll dann festgestellt werden, ob und wann die Maus das Control verläßt? Man könnte zwar auf das MouseMove-Ereignis des Formulars zurückgreifen, aber leider arbeitet diese Methode nicht zuverlässig: Wird z.B. der Mauszeiger schnell von einem Control in ein anderes gezogen (oder gar ganz aus dem Formular hinaus), so bekommt das Formular überhaupt kein Ereignis mit.

Lösung

Zum Glück stellt die Windows-API Hilfsmittel zur Verfügung, um ein Control zu "verfolgen" (engl. "to capture"). Damit werden alle MouseMove-Ereignisse immer an dieses eine Control gesendet, egal wo die Maus gerade steht.

Mit der unten vorgestellten MouseOverState-Funktion wird für ein gegebenes Control ctl überprüft, ob die Maus gerade darüber "schwebt". Falls nein, so gibt die Funktion vbLeave zurück. Wird das Control bereits verfolgt, so gibt die Funktion vbOver zurück, ansonsten wird die Verfolgung iniziiert und ein vbEnter zurückgegeben (s.a. Online-Hilfe zum DragOver-Ereignis).

Beispiel

Im diesem Beispiel wechselt die Beschriftung des CommandButtons cmdTest folgendermaßen: Fährt die Maus in die Schaltfläche rein, so erscheint "in"; Wird die Maus innerhalb des Buttons bewegt, so ertönt (zu Testzwecken) ein akustisches Signal; Verläßt der Mauscursor die Schaltfläche, so erscheint "out".

Private Sub cmdTest_MouseMove(Button As Integer, _
    Shift As Integer, X As Single, Y As Single)
  
  Select Case MouseOverState(cmdTest)
  Case vbEnter
    cmdTest.Caption = "in"
  Case vbOver
    Beep 'Test
  Case vbLeave
    cmdTest.Caption = "out"
  End Select

End Sub

Code

Im Deklarationsteil eines Moduls oder Formulars müssen folgende API-Routinen zur Verfügung gestellt werden:

Private Type POINTAPI
  X As Long
  Y As Long
End Type

Private Declare Function GetCursorPos Lib "user32" ( _
    lpPoint As POINTAPI) As Long
Private Declare Function WindowFromPoint Lib "user32" ( _
    ByVal xPoint As Long, ByVal yPoint As Long) As Long
Private Declare Function GetCapture Lib "user32" ( _
    ) As Long
Private Declare Function SetCapture Lib "user32" ( _
    ByVal hWnd As Long) As Long
Private Declare Function ReleaseCapture Lib "user32" ( _
    ) As Long

Die eigentliche Funktion sieht dann folgendermaßen aus:

Public Function MouseOverState( _
    ByRef ctl As Control _
  ) As DragOverConstants
  
  'Deklarationen:
  Dim Point As POINTAPI
  Dim Window As Long
  
  'hWnd des Controls unter der Maus bestimmen:
  GetCursorPos Point
  Window = WindowFromPoint(Point.X, Point.Y)
  
  'Handles vergleichen:
  If ctl.hWnd = Window Then
  
    'Feststellen, ob Control gewechselt hat:
    If GetCapture() <> Window Then
    
      'Verfolgung starten:
      SetCapture Window
      MouseOverState = vbEnter
    
    Else
    
      'Verfolgung fortsetzen:
      MouseOverState = vbOver
    
    End If
  
  Else
  
    'Verfolgung stoppen:
    ReleaseCapture
    MouseOverState = vbLeave
  
  End If 'ctl.hWnd = Window
End Function

© Jost Schwider, 31.03.2001-31.03.2001 - http://vb-tec.de/mausover.htm