ABOUT Visual Basic Programmieren Programmierung Download Downloads Tips & Tricks Tipps & Tricks Know-How Praxis VB VBA Visual Basic for Applications VBS VBScript Scripting Windows ActiveX COM OLE API ComputerPC Microsoft Office Microsoft Office 97 Office 2000 Access Word Winword Excel Outlook Addins ASP Active Server Pages COMAddIns ActiveX-Controls OCX UserControl UserDocument Komponenten DLL EXE
Diese Seite wurde zuletzt aktualisiert am 19.12.2002

Diese Seite wurde zuletzt aktualisiert am 19.12.2002
Aktuell im ABOUT Visual Basic-MagazinGrundlagenwissen und TechnologienKnow How, Tipps und Tricks rund um Visual BasicActiveX-Komponenten, Controls, Klassen und mehr...AddIns für die Visual Basic-IDE und die VBA-IDEVBA-Programmierung in MS-Office und anderen AnwendungenScripting-Praxis für den Windows Scripting Host und das Scripting-ControlTools, Komponenten und Dienstleistungen des MarktesRessourcen für Programmierer (Bücher, Job-Börse)Dies&Das...

Themen und Stichwörter im ABOUT Visual Basic-Magazin
Code, Beispiele, Komponenten, Tools im Überblick, Shareware, Freeware
Ihre Service-Seite, Termine, Job-Börse
Melden Sie sich an, um in den vollen Genuss des ABOUT Visual Basic-Magazins zu kommen!
Informationen zum ABOUT Visual Basic-Magazin, Kontakt und Impressum

Zurück...

Combo mit Hover-Klappe

Zurück...


Anzeige

(-hg) mailto:hg_autocombo@aboutvb.de

Ein nettes Feature hinsichtlich des Bedienungskomforts sind ComboBoxen, die beim Überstreichen mit dem Mauszeiger automatisch aus- und wieder einklappen. Mit Hilfe von ein paar wenigen API-Funktionen und eines Timers ist das gar nicht so schwierig zu realisieren. Allerdings sollten Sie dieses Feature sparsam einsetzen. Der Effekt wird nämlich leicht lästig, wenn solche Automatik-ComboBoxen - vor allem in größerer Anzahl - quer über Ihr Form verstreut sind: Jeder Versuch des Anwenders, ein Menü oder die Toolbar oben im Form zu erreichen, artet dann nur zu leicht in ein regelrechtes "Gewitter" von auf- und zuklappenden ComboBoxen aus.

Das Prinzip ist einfach: Im Timer-Ereignis eines schnellen Timers (mit einem kurzen Intervall von beispielsweise 50 ms) wird geprüft, ob sich der Mauszeiger über der ComboBox befindet. Ist dies der Fall, wird die Liste der ComboBox ausgeklappt (siehe dazu auch: "Klappe auf - Klappe zu").

Zur Prüfung wird zunächst mittels der API-Funktion GetCursorPos die aktuelle Mauszeiger-Position ermittelt. Im zweiten Schritt wird festgestellt, ob das zu diesem Punkt von der API-Funktion WindowFromPoint gelieferte Fenster-Handle dasjenige der ComboBox ist. Bei einer ComboBox mit dem Stil "0 - Dropdown-Kombinationsfeld" ist es allerdings nicht ganz so einfach, da sich der Mauszeiger ja über dem Eingabefeld (einer TextBox) der ComboBox befinden kann. Daher ist zusätzlich zu prüfen, ob das Elternfenster des zur aktuellen Mauszeiger-Position ermittelten Fenster-Handles die betreffende ComboBox ist.

Ist die Liste der ComboBox ausgeklappt, wird von nun an im Timer-Ereignis geprüft, ob sich der Mauszeiger immer noch über der ComboBox oder ob er sich über der ausgeklappten Liste befindet. Ist weder das eine noch das andere der Fall, wird die Liste wieder eingeklappt.

Für den ersten Fall ist die Prüfung die gleiche wie schon beschrieben. Der zweite Fall ist jedoch nicht so einfach zu erledigen. Denn hier muss zusätzlich das Handle der ausgeklappten Liste ermittelt werden. Da wir auch nicht wissen können, ob die Liste nach oben oder ob sie nach unten ausgeklappt worden ist, müssen wir beide Richtungen berücksichtigen.

Mit einem kleinen Trick können wir aber auch dies in Erfahrung bringen - und zugleich auch das Fenster-Handle der Liste. Da sich die ausgeklappte Liste in aller Regel unmittelbar an die ComboBox anschließt, ermitteln wir vorbeugend bei noch geschlossener Liste die Fenster-Handles zu einem Punkt oberhalb der ComboBox, etwa in der horizontalen Mitte mit 2 Pixels Abstand, und spiegelbildlich dazu zu einem Punkt unterhalb der ComboBox. Diese beiden Fenster-Handles werden in (modul-)globalen Hilfsvariablen vorgemerkt.

Wird nun die Liste ausgeklappt, wird sie einen dieser beiden Punkte überdecken. Nach der Ermittlung der aktuellen Fenster-Handles unter diesen beiden Punkten prüfen wir, welches der beiden aktuellen Handles nicht mehr mit den vorgemerkten Handles übereinstimmt: Dieses wird das Handle der Ausklappliste sein.

Nun brauchen wir nur noch zu prüfen, ob sich die aktuelle Mauszeiger-Position über dem Fenster der Ausklappliste befindet. Befindet sich der Mauszeiger weder über der ComboBox noch über der Ausklappliste, wird die Liste wieder geschlossen.

Der Einfachheit halber verpacken Sie das Ganze am besten in eine Klasse, die Sie für jede ComboBox einmal instanzieren. In einer Init-Methode übergeben Sie einer Instanz eine Referenz auf die betreffende ComboBox und eine Referenz auf den Timer (einer reicht für alle ComboBoxen). Zusätzlich können Sie angeben, ob der Automatismus aktiviert sein soll, und ob die ComboBox beim automatischen Ausklappen auch zugleich den Fokus erhalten soll.

Den Automatismus können Sie jederzeit über die Eigenschaft Auto an- oder abstellen. Das Setzen des Fokus können Sie über die Eigenschaft SetFocusOnAutoOpen festlegen.

So lange der Automatismus aktiviert ist, empfängt die Klasse die Timer-Ereignisse direkt. Jede Instanz der Klasse reagiert somit individuell für die ihr zugewiesene ComboBox.

Private Type POINTAPI
  x As Long
  y As Long
End Type

Private Type RECT
  Left As Long
  Top As Long
  Right As Long
  Bottom As Long
End Type

Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetWindowRect Lib "user32" _
 (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
 (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _
 lParam As Any) As Long
Private Declare Function WindowFromPoint Lib "user32" _
 (ByVal xPoint As Long, ByVal yPoint As Long) As Long

Private WithEvents eTimer As Timer

Private mAutoOpened As Boolean
Private mCombo As ComboBox
Private mInitDone As Boolean
Private mTimer As Timer
Private mWndAbove As Long
Private mWndBelow As Long

Private pAuto As Boolean
Private pSetFocusOnAutoOpen As Boolean

Public Property Get Auto() As Boolean
  Auto = pAuto
End Property

Public Property Let Auto(New_Auto As Boolean)
  Select Case New_Auto
    Case pAuto
    Case Else
      pAuto = New_Auto
      If pAuto Then
        Set eTimer = mTimer
      Else
        Set eTimer = Nothing
      End If
  End Select
End Property

Public Property Get SetFocusOnAutoOpen() As Boolean
  SetFocusOnAutoOpen = pSetFocusOnAutoOpen
End Property

Public Property Let SetFocusOnAutoOpen(New_SetFocusOnAutoOpen As Boolean)
  pSetFocusOnAutoOpen = New_SetFocusOnAutoOpen
End Property

Public Sub Init(Combo As ComboBox, Timer As Timer, _
 Optional ByVal Auto As Boolean = True, _
 Optional ByVal SetFocusOnAutoOpen = True)

  Set mCombo = Combo
  Set mTimer = Timer
  pSetFocusOnAutoOpen = SetFocusOnAutoOpen
  pAuto = Auto
  If pAuto Then
    Set eTimer = mTimer
  End If
End Sub

Public Sub Refresh()
  zInit
End Sub

Private Sub Class_Terminate()
  Set eTimer = Nothing
  Set mTimer = Nothing
  Set mCombo = Nothing
End Sub

Private Sub eTimer_Timer()
  Dim nRect As RECT
  Dim nPoint As POINTAPI
  Dim nWndAbove As Long
  Dim nWndBelow As Long
  Dim nWnd As Long
  Dim nTestWnd As Long
  Dim nComboWnd As Long
  
  Const CB_GETDROPPEDSTATE = &H157
  Const CB_SHOWDROPDOWN = &H14F
  
  With mCombo
    GetCursorPos nPoint
    With nPoint
      nTestWnd = WindowFromPoint(.x, .y)
    End With
    nComboWnd = .hwnd
    If CBool(SendMessage(nComboWnd, CB_GETDROPPEDSTATE, 0, 0)) Then
      If mAutoOpened Then
        If .Style = 0 Then
          If nTestWnd = nComboWnd Then
            Exit Sub
          ElseIf GetParent(nTestWnd) = nComboWnd Then
            Exit Sub
          End If
        Else
          If nTestWnd = nComboWnd Then
            Exit Sub
          End If
        End If
        GetWindowRect nComboWnd, nRect
        With nRect
          .Right = .Left + ((.Right - .Left) \ 2)
          nWndAbove = WindowFromPoint(.Right, .Top - 2)
          nWndBelow = WindowFromPoint(.Right, .Bottom + 2)
          Select Case True
            Case nWndAbove <> mWndAbove
              nWnd = nWndAbove
            Case nWndBelow <> mWndBelow
              nWnd = nWndBelow
          End Select
          If nWnd Then
            If nTestWnd <> nWnd Then
              SendMessage nComboWnd, CB_SHOWDROPDOWN, False, 0
              mAutoOpened = False
              zInit
            End If
          End If
        End With
      End If
    Else
      zInit
      If .Style = 0 Then
        If nTestWnd <> nComboWnd Then
          If GetParent(nTestWnd) <> nComboWnd Then
            Exit Sub
          End If
        End If
      Else
        If nTestWnd <> .hwnd Then
          Exit Sub
        End If
      End If
      If pSetFocusOnAutoOpen Then
        .SetFocus
      End If
      mAutoOpened = True
      SendMessage nComboWnd, CB_SHOWDROPDOWN, True, 0
      .MousePointer = vbDefault
    End If
  End With
End Sub

Private Sub zInit()
  Dim nRect As RECT
  
  GetWindowRect mCombo.hwnd, nRect
  With nRect
    .Right = .Left + ((.Right - .Left) \ 2)
    mWndAbove = WindowFromPoint(.Right, .Top - 2)
    mWndBelow = WindowFromPoint(.Right, .Bottom + 2)
  End With
End Sub

Beispiel-Projekt und Klasse clsAutoCombo (autocombo.zip - ca. 4 KB)


Artikel
Zum Download-Bereich dieses Artikel
Mail an den Autor dieses Artikels

KnowHow
Zur KnowHow-Übersicht

KnowHow-Themen
Themen - Allgemeines
Themen - Entwicklungsumgebung (VB-IDE)
Themen - Forms
Themen - Steuerelemente (Controls)
Themen - Grafik
Themen - Dateien
Themen - UserControls
Themen - Einsteiger-Tipps
Themen - Wussten Sie...?

Übersicht nach Titeln in alphabetischer Reihenfolge
Übersicht nach Erscheinungsdatum

Schnellsuche




Zum Seitenanfang

Copyright © 1999 - 2017 Harald M. Genauck, ip-pro gmbh  /  Impressum

Zum Seitenanfang

Zurück...

Zurück...

Download Internet Explorer