|
Ob beim "klassischen" VB-Drag&Drop,
beim OLE-Drag&Drop oder bei irgendwelchen anderen
Ziehvorgängen mit der Maus - der Zieh-Vorgang sollte nach dem
Niederdrücken der Maustaste erst nach einer kleinen Verschiebung
des Mauszeigers anspringen. Dadurch ist es möglich, dass Sie
unterscheiden können, ob der Anwender das betreffende Objekt
lediglich zum Markieren oder Auswählen angeklickt hat, oder ob er
tatsächlich einen Ziehvorgang einleiten möchte.
Wie aber sollten Sie beim Niederdrücken der Maustaste, also beim
Eintreffen des MouseDown-Ereignisses bereits erahnen können, ob der
Anwender den Mauszeiger noch bewegen wird oder nicht? Natürlich
könnten Sie etwa im MouseDown-Ereignis die Position des Mauszeigers
festhalten und in den eventuell eintreffenden nachfolgenden
MouseMove-Ereignissen prüfen, ob sich der Mauszeiger mindestens um
eine bestimmte Distanz in horizontaler und/oder vertikaler Richtung
verschoben hat. Ist das der Fall, leiten Sie den Ziehvorgang ein.
Anderenfalls führen Sie im MouseUp- oder im Click-Ereignis die
eigentliche, reine Anklick-Funktionalität aus. Die vom System her
vorgesehene minimale Bewegungsdistanz können Sie über die
API-Funktion GetSystemMetrics
und deren Kennungen SM_CXDRAG und SM_CYDRAG ermitteln.
Sie können den ganzen Prüfungsvorgang aber auch einschließlich
der Berücksichtigung der systemkonformen Distanz bereits im
MouseDown-Ereignis der API-Funktion DragDetect
überlassen. Sie übergeben dieser Funktion das Fenster-Handle des
betreffenden Objekts und die aktuelle Mauszeiger-Position. Sie
können hier allerdings nicht die vom MouseDown-Ereignis
übergebenen X- und Y-Koordinaten
verwenden, da hier auf den ganzen Bildschirm bezogene Werte erwartet
werden - diese können Sie mit der API-Funktion GetCursorPos
unmittelbar vorher ermitteln. Die Funktion wartet mit der Rückkehr
so lange, bis entweder die Maustaste wieder an Ort und Stelle
losgelassen oder bis der Mauszeiger um die eingestellte Distanz
bewegt wurde. Im ersteren Fall ist der Rückgabewert 0
und Sie könnten hier zum Ziehvorgang alternativ auszuführenden
Code unterbringen, und auch den Code, der sonst im nun nicht mehr
ausgelösten MouseUp-Ereignis zu bearbeiten wäre. Ist der
Mauszeiger genügend weit bewegt worden, gibt die Funktion 1
zurück und der Ziehvorgang sollte eingeleitet werden. Die weiteren
Mausereignisse sowohl beim VB-Drag&Drop als auch
beim OLE-Drag&Drop werden dann vom System selbst
verwaltet.
Da Sie unbedingt die aktuelle Mauszeiger-Position benötigen und
daher die Funktion GetCursorPos immer unmittelbar vorher aufrufen
sollten, stecken wir die beiden zusammengehörenden Aufrufe in eine
Hilfs-Funktion. Sie übergeben dieser das erwartete Fenster-Handle
und erhalten True als Rückgabewert, wenn der Mauszeiger
entsprechend bewegt worden war.
Wundern Sie sich nicht über gegebenenfalls abweichende
Deklarationen der Funktion DragDetect, denen Sie anderenorts
vielleicht begegnen (etwa im VB-API-Viewer - dort ist
die Übergabe der Mausposition als benutzerdefinierte Variable des
Typs POINTAPI deklariert). Sowohl die Funktion (als wohl auch die
Deklarateure des API-Viewers) scheinen auf den ersten Blick noch in
der 16-Bit-Welt zu leben und die Koordinaten des
Mauszeigers als Integer-Wertepaar zu erwarten. Die Funktion ist ja
aber eigentlich nicht für Visual Basic geschrieben worden, sondern
zur Verwendung in der Fenster-Prozedur eines in C
geschriebenen Windows-Programms gedacht gewesen. Und dort werden mit
den Maus-Nachrichten die Koordinaten im höher- und niederwertigen
Wort eines Long-Integers zusammengefasst angeliefert und können so
direkt weitergereicht werden. In der 16-Bit-Welt
entsprach das durchaus zufällig der damals gültigen Deklaration
des Datentyps POINTAPI mit zwei Integer-Elementen - aber nicht mehr
der heutigen mit zwei Long-Elementen. Der Versuch der direkten
Übergabe in der heutigen Form, wie sie für die Funktion
GetCursorPos benötigt wird, scheitert und wird von VB mit der
Fehlermeldung "Falsche DLL-Aufrufkonvention" quittiert.
Der Versuch, zusätzlich noch die alte Zwei-Integer-Version zu
deklarieren und zu verwenden, scheitert jedoch gleichermaßen. Die
ausdrückliche Zerlegung der Deklaration in zwei separate
Integer-Parameter funktioniert hingegen.
Private Type POINTAPI
X As Long
Y As Long
End Type
Private Declare Function DragDetect Lib "user32" _
(ByVal hWnd As Long, ByVal px As Integer, _
ByVal py As Integer) As Long
Private Declare Function GetCursorPos Lib "user32" _
(lpPoint As POINTAPI) As Long
Public Function BeginDrag(hWnd As Long) As Boolean
Dim nPoint As POINTAPI
GetCursorPos nPoint
BeginDrag = CBool(DragDetect(hWnd, CInt(nPoint.X), CInt(nPoint.Y)))
End Function
Der Aufruf im MouseDown-Ereignis einer PictureBox sähe etwa wie
folgend aus:
Private Sub Picture1_MouseDown(Button As Integer, _
Shift As Integer, X As Single, Y As Single)
If Button Then
If BeginDrag(Me.hWnd) Then
Picture1.Drag
End If
End If
End Sub
|