|
Drag&Drop ist eine bequeme Angelegenheit, auch beim
TreeView-Steuerelement aus den Microsoft Common Controls. Und wenn
der dargestellte Baum zu hoch oder zu breit ist, erreichen Sie den
gewünschten Zielknoten nicht, weil die Darstellung nicht
automatisch mitrollt, wenn Sie den Mauszeiger in die Randbereiche
des Steuerelements bewegen. Allerdings ist es kein Problem, ein
TreeView-Steuerelement zum Rollen zu bringen. Sie brauchen ihm nur
über die API-Funktion SendMessage
die Nachrichten WM_VSCROLL
für vertikales Rollen und WM_HSCROLL
für horizontales Rollen zu senden, wenn der Mauszeiger in die
Randbereiche gerät. Dazu geben Sie noch den gewünschten
Bewegungsumfang an - SB_LINEDOWN oder SB_LINEUP für je einen Knoten
auf- oder abwärts, SB_LINELEFT oder SB_LINERIGHT für etwa ein
Zeichen nach links oder rechts. Sie können diese Nachrichten sogar
auch dann unbesorgt senden, wenn kein Rollen in die betreffende
Richtung mehr möglich ist - in diesem Fall passiert einfach gar
nichts.
Die Randbereiche legen Sie anhand des inneren Rechtecks des
TreeViews fest. Dieses innere Rechteck erhalten Sie über die
API-Funktion GetClientRect,
die auch gegebenenfalls sichtbare Rollbalken berücksichtigt und nur
die tatsächliche Fläche zurückgibt, innerhalb derer die Knoten im
TreeView dargestellt werden. Sie ersparen sich damit mühselige
Rechnerei und die Ermittlung der Rollbalkengrößen und
dreidimensionalen Rahmenstärken.
Da das TreeView-Steuerelement beim horizontalen Rollen die
Darstellung des Fokus-Rechtecks nicht sauber aktualisiert, wenn sich
der aktuell markierte Knoten im Rollbereich befindet, sollte nach
jedem Rollschritt die Darstellung über die Refresh-Methode des
TreeViews aufgefrischt werden. Damit die Darstellung jedoch nicht
flackert, falls Sie eine Rollnachricht absenden, obwohl in die
gewünschte Richtung gar nicht mehr weiter gerollt werden kann,
ermitteln Sie zuvor über die API-Funktion GetScrollPos
die aktuelle Rollposition, und vergleichen diese mit der nach dem
Absenden der Nachricht erneut ermittelten Rollposition. Hat sich
diese nicht geändert, erübrigt sich die Auffrischung.
Die folgende Hilfsprozedur TreeViewScroll erledigt die ganze
Ermittelei und Rechnerei für Sie. Sie übergeben ihr im ersten
Parameter das betreffende TreeView-Steuerelement, dann die Koordinaten
x und y, wie sie Ihnen beispielsweise vom
OLEDragOver-Ereignis geliefert werden. Im letzten, optionalen
Parameter ScrollRegion können Sie die Empfindlichkeit (die Breite)
der Randbereiche festlegen. Voreingestellt ist eine Breite von 3
Pixels. Sie können auch andere Werte angeben. Bedenken Sie
jedoch, dass es bei Werten, die sich an die Höhe eines Knotens
annähern, ziemlich schwierig werden dürfte, einen Knoten als
Ablageziel zu treffen, wenn er immer gleich unter dem Mauszeiger
weggerollt wird.
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare Function GetClientRect Lib "user32" _
(ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function GetScrollPos Lib "user32" _
(ByVal hwnd As Long, ByVal nBar As Long) As Long
Private Declare Function SendMessageLong Lib "user32" _
Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
Public Sub TreeViewScroll(TreeView As TreeView, _
ByVal x As Single, ByVal y As Single, _
Optional ByVal ScrollRegion As Long = 3)
Dim nRect As RECT
Dim nScrollRegion As Single
Dim nScrollPos As Long
Dim nWnd As Long
Const SB_HORZ = 0
Const SB_LINEDOWN = 1
Const SB_LINELEFT = 0
Const SB_LINERIGHT = 1
Const SB_LINEUP = 0
Const WM_HSCROLL = &H114
Const WM_VSCROLL = &H115
With TreeView
nWnd = .hwnd
GetClientRect nWnd, nRect
nRect.Bottom = nRect.Bottom * Screen.TwipsPerPixelY
nScrollRegion = ScrollRegion * Screen.TwipsPerPixelY
Select Case y
Case 1 To nScrollRegion
SendMessageLong nWnd, WM_VSCROLL, SB_LINEUP, 0
Case Is >= nRect.Bottom - nScrollRegion
SendMessageLong nWnd, WM_VSCROLL, SB_LINEDOWN, 0
Case Else
nRect.Right = nRect.Right * Screen.TwipsPerPixelX
nScrollRegion = ScrollRegion * Screen.TwipsPerPixelX
Select Case x
Case 1 To nScrollRegion
nScrollPos = GetScrollPos(nWnd, SB_HORZ)
SendMessageLong nWnd, WM_HSCROLL, SB_LINELEFT, 0
If nScrollPos <> GetScrollPos(nWnd, SB_HORZ) Then
.Refresh
End If
Case Is >= nRect.Right - nScrollRegion
nScrollPos = GetScrollPos(nWnd, SB_HORZ)
SendMessageLong nWnd, WM_HSCROLL, SB_LINERIGHT, 0
If nScrollPos <> GetScrollPos(nWnd, SB_HORZ) Then
.Refresh
End If
End Select
End Select
End With
End Sub
Ein Aufruf im OLEDragOver-Ereignis sähe beispielsweise so aus:
Private Sub TreeView1_OLEDragOver(Data As MSComctlLib.DataObject, _
Effect As Long, Button As Integer, Shift As Integer, _
x As Single, y As Single, State As Integer)
' ...
TreeViewScroll TreeView1, x, y
' ...
End Sub
|