|
Das Form_Resize-Ereignis informiert Sie zwar über die Änderung der Größe eines Forms einschließlich eines Wechsels des Fensterstatus (WindowState). Zur Meldung eines reinen Verschiebens eines Forms gibt es jedoch kein Ereignis. Subclassing-Techniken und das Abfangen der Nachricht WM_MOVING sind eine Möglichkeit, die allerdings nicht jedermanns Sache sind. Es gibt aber auch eine etwas trickreiche, fast reine VB-Möglichkeit, die mit zwei einfachen Windows-API-Aufrufen auskommt.
Wir machen uns zu Nutze, dass die Fläche hinter einem Form (zumindest teilweise) neu gezeichnet werden muss, wenn dieses Form verschoben wird. Hinter das zu verschiebende Form legen wir einfach ein weiteres (rahmenloses) Überwachungs-Form und nutzen so dessen Paint-Ereignis als Benachrichtigung über ein Verschieben des darüber liegenden Forms. Ist dieses Form verschoben, brauchen wir lediglich wieder Position (und gegebenenfalls Größe) des Überwachungs-Forms nachzuführen. Damit das Überwachungs-Form immer hinter dem eigentlichen Form bleibt und sich auch kein anderes Form oder Fenster dazwischen schieben kann, machen wir das Überwachungs-Form beim Show-Aufruf zum Besitzer des zu überwachenden Forms.
Da noch ein paar weitere Kleinigkeiten zu beachten sind, wie etwa zum sauberen gleichzeitigen Entladen beider Forms (Entkoppelung über einen Timer) oder zur Anpassung der Größe des Überwachungs-Forms bei Größenänderungen des überwachten Forms, packen wir alle benötigte Funktionalität in das Code-Modul des Überwachungs-Forms. Dieses überwacht selbst die relevanten Ereignisse des zu überwachenden Forms, indem es diese Ereignisse einfach belauscht (siehe "Lausch-Eingriffe").
Der Einsatz eines solchen Überwachungsforms ist einfach. Im Form_Load-Ereignis instanzieren Sie das Form frmFormMoveEvent und rufen sogleich dessen Init-Methode auf, der sich das zu überwachende Form selbst als Parameter mitgibt. Da die Form-Komponente der Instanz geladen wird, bleibt die Instanz auch über das Ende der Prozedur hinaus erhalten.
Private Sub Form_Load()
With New frmFormMoveEvent
.Init Me
End With
End Sub
Weiterhin brauchen Sie das zu überwachende Form nur noch mit der öffentlichen Methode SizeMove zu versehen:
Public Sub SizeMove()
'...
End Sub
Der Code des Forms frmFormMoveEvent:
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare Function EqualRect Lib "user32" _
(lpRect1 As RECT, lpRect2 As RECT) As Long
Private Declare Function GetWindowRect Lib "user32" _
(ByVal hwnd As Long, lpRect As RECT) As Long
Private mLastRect As RECT
Private mInUnload As Boolean
Private WithEvents eForm As Form
Public Sub Init(Form As Form)
Set eForm = Form
Me.Show
eForm.Show , Me
End Sub
Public Sub Reshow()
zCheckSizeMove
eForm.Show
End Sub
Private Sub eForm_QueryUnload(Cancel As Integer, _
UnloadMode As Integer)
If Not mInUnload Then
Cancel = True
tmr.Enabled = True
End If
End Sub
Private Sub eForm_Resize()
zCheckSizeMove
End Sub
Private Sub Form_Paint()
zCheckSizeMove
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, _
UnloadMode As Integer)
Set eForm = Nothing
End Sub
Private Sub tmr_Timer()
tmr.Enabled = False
mInUnload = True
Unload Me
End Sub
In der folgenden Funktion findet die eigentliche Auslösung des SizeMove-Ereignisses statt. Befindet sich das zu überwachende Form im Normalzustand (WindowState = vbNormal) und ist es sichtbar, werden zunächst Größe und Position des Überwachungsfensters dem zu überwachenden Fenster angepasst. Nun wird mit der API-Funktion GetWindowRect das absolute Rechteck des Überwachbungs-Forms ermittelt und mit dem in mLastRect abgelegten Rechteck über die API-Funktion EqualRect verglichen. Hat sich das Rechteck geändert, wird die öffentliche Methode SizeMove des zu überwachenden Forms aufgerufen. Dann wird mLastRect aktualisiert und die Prozedur wird verlassen. Ist das zu überwachende Form hingegen nicht sichtbar oder minimiert oder maximiert, wird das Überwachungs-Form verborgen. Die SizeMove-Methode wird aufgerufen und mLastRect wird auf ein leeres Rechteck gesetzt.
Private Sub zCheckSizeMove()
Dim nRect As RECT
With eForm
Select Case .WindowState
Case vbNormal
If .Visible Then
Me.Move .Left, .Top, .Width, .Height
With Me
.Visible = True
GetWindowRect .hwnd, nRect
End With
If Not CBool(EqualRect(nRect, mLastRect)) Then
.SizeMove
LSet mLastRect = nRect
End If
Exit Sub
End If
End Select
Me.Visible = False
.SizeMove
LSet mLastRect = nRect
End With
End Sub
|