|
Eine Fortschrittsanzeige in der Statuszeile? Oder irgend ein anderes Steuerelement in einer Anzeigefläche der Statuszeile? Anders gefragt: Wie bekommen Sie ein Steuerelement in eine Panel-Fläche eines StatusBar-Steuerelements (aus den Microsoft Common Controls) hinein?
Eine Möglichkeit wäre, das Steuerelement an die Position der Panel-Fläche zu schieben. Die linke Kante und die Breite liefert die Panel-Fläche selbst. Der Abstand der Oberkante innerhalb des StatusBar-Elements ist automatisch festgelegt, wie sich auch die Höhe automatisch aus der Höhe des StatusBar-Elements ergibt. Mit der Methode ZOrder des ProgressBar-Elements setzen Sie dieses in den Vordergrund.
Befindet sich die StatusBar jedoch in einem MDI-Hauptform, geht das nicht ganz so einfach. Denn dort müssten Sie das Steuerelement erst einmal außerhalb der StatusBar platzieren. Denn selbst wenn es ein Steuerelement wäre, das über die Align-Eigenschaft verfügt und sich so direkt auf einem MDI-Hauptform platzieren ließe, könnte es nicht verschoben werden. Hier müssen Sie eine zusätzliche PictureBox einfügen. Deren Visible-Eigenschaft setzen Sie auf False, falls Sie die PictureBox nicht anderweitig sichtbar benötigen und platzieren auf ihr das bzw. die in die StatusBar einzufügenden Steuerelement(e) auf dieser PictureBox.
Damit haben wir nun das Problem gelöst, ein Steuerelement frei beweglich zu halten, aber zugleich haben wir uns das Problem eingehandelt, dass sich die StatusBar und das Steuerelement nicht länger im gleichen Container befinden, und daher das Steuerelement so nicht mehr über die StatusBar geschoben werden kann.
Allerdings können wir Steuerelemente, die uns ihr Fenster-Handle zur Verfügung stellen (hWnd-Eigenschaft), der StatusBar mittels der API-Funktion SetParent als Kind-Fenster "unterjubeln". Und nachdem ein Steuerelement so zu einem Kind der StatusBar geworden ist, können wir es darin an der gewünschten Stelle platzieren. Bei einem normalen Form wäre das zwar nicht notwendig - aber es schadet auch nichts. Daher können wir für beide Fälle ein und dasselbe Verfahren verwenden.
Die Funktion SetPanelControl übernimmt nicht nur die reine Platzierung über genau einer bestimmten Panel-Fläche der StatusBar, sondern sie berücksichtigt bei der Berechnung der Position auch die ScaleMode-Einstellung des Forms bzw. der PictureBox, auf dem sich das zu platzierende Steuerelement zu Beginn befindet. Sie übergeben ihr das zu platzierende Steuerelement und die StatusBar in den ersten beiden Parametern. Im Parameter PanelKey übergeben Sie entweder den Index oder den Schlüssel eines der Panels der StatusBar, oder gar direkt ein bestimmtes Panel. Im optionalen Parameter AdjustStatusBarToControl können Sie festlegen, ob die Höhe der StatusBar an das zu platzierende Steuerelement angepasst werden soll - dies ist beispielsweise bei ComboBoxen sinnvoll, deren Höhe nicht willkürlich geändert werden kann.
Wie beschrieben wird mittels SetParent das Fenster der StatusBar als Eltern-Fenster des Steuerelements gesetzt. Da es Steuerelemente gibt, die beim Entladen eines Forms Probleme bereiten, wenn sie sich dann nicht in ihrem ursprünglichen Eltern-Fenster befinden, sollte das Handle des ursprünglichen Eltern-Fensters, das von der SetParent-Funktion zurückgegeben wird, festgehalten werden. Damit Sie sich nicht um die Verwaltung dieses Handles zu kümmern brauchen, können Sie es in den meisten Fällen im User-Data-Feld des Steuerelement-Fensters ablegen (siehe "Extra-Tag per API" khwextratag.htm). Es gibt allerdings Steuerelemente, die dieses Datenfeld selbst mit Beschlag belegen. Ist dies der Fall, übergibt Ihnen SetPanelControl das Handle als Rückgabewert - in diesem Fall müssen Sie sich selbst um die Ablage kümmern. Ein solches Steuerelement ist übrigens Das ProgressBar-Steuerelement aus den Microsoft Common Controls. Die eigentliche Platzierung des Seuerlements erfolgt über die private Hilfsfunktion des Moduls zAdjust.
Private Declare Function GetWindowLong Lib "user32" _
Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) _
As Long
Private Declare Function SetParent Lib "user32" _
(ByVal hWndChild As Long, ByVal hWndNewParent As Long) As Long
Private Declare Function SetWindowLong Lib "user32" _
Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, _
ByVal dwNewLong As Any) As Long
Private Const GWL_USERDATA = (-21)
Public Enum PanelControlErrorConstants
pcErrInvalidPanelObject = 10001
pcErrInvalidPanelIndexKey = 10002
End Enum
Public Function SetPanelControl(Control As Control, _
StatusBar As StatusBar, PanelKey As Variant, _
Optional ByVal AdjustStatusBarToControl As Boolean) As Long
Dim nParent As Object
Dim nControl As Control
Dim nOldParentWnd As Long
Dim nPanel As Panel
With Control
If TypeOf .Parent Is MDIForm Then
Set nParent = .Container
Else
Set nParent = .Parent
End If
End With
If IsObject(PanelKey) Then
If TypeOf PanelKey Is Panel Then
Set nPanel = PanelKey
Else
Err.Raise pcErrInvalidPanelObject, "SetPanelControl"
End If
End If
On Error Resume Next
If nPanel Is Nothing Then
Set nPanel = StatusBar.Panels(PanelKey)
If Err.Number Then
Err.Raise pcErrInvalidPanelIndexKey, "SetPanelControl"
End If
End If
On Error GoTo 0
With Control
nOldParentWnd = SetParent(.hWnd, StatusBar.hWnd)
If GetWindowLong(.hWnd, GWL_USERDATA) = 0 Then
SetWindowLong .hWnd, GWL_USERDATA, nOldParentWnd
Else
SetPanelControl = nOldParentWnd
End If
End With
zAdjust Control, nParent, nPanel, StatusBar, _
AdjustStatusBarToControl
End Function
Private Sub zAdjust(Control As Control, Parent As Object, _
Panel As Panel, StatusBar As StatusBar, _
ByVal AdjustStatusBarToControl As Boolean)
On Error Resume Next
With Parent
If AdjustStatusBarToControl Then
StatusBar.Height = Control.Height + .ScaleY(6, vbPixels)
If Panel.Index = 1 Then
Control.Move Panel.Left + .ScaleX(1, vbPixels), _
.ScaleY(4, vbPixels), Panel.Width - .ScaleX(3, vbPixels)
Else
Control.Move Panel.Left + .ScaleX(3, vbPixels), _
.ScaleY(4, vbPixels), Panel.Width - .ScaleX(4, vbPixels)
End If
Else
If Panel.Index = 1 Then
Control.Move Panel.Left + .ScaleX(1, vbPixels), _
.ScaleY(4, vbPixels), Panel.Width - .ScaleX(3, vbPixels), _
StatusBar.Height - .ScaleY(6, vbPixels)
Else
Control.Move Panel.Left + .ScaleX(3, vbPixels), _
.ScaleY(4, vbPixels), Panel.Width - .ScaleX(4, vbPixels), _
StatusBar.Height - .ScaleY(6, vbPixels)
End If
End If
End With
End Sub
Der Rückwärtsgang, nämlich das Entfernen eines Steuerelements aus der StatusBar, erfolgt über die Prozedur RemovePanelControl. Ihr übergeben Sie das zu entfernende Steuerelement und gegebenenfalls das von Ihnen selbst gesicherte ursprüngliche Fenster-Handle.
Public Sub RemovePanelControl(Control As Control, _
Optional OldParentWnd As Long)
With Control
.Visible = False
If OldParentWnd Then
SetParent .hWnd, OldParentWnd
Else
SetParent .hWnd, GetWindowLong(.hWnd, GWL_USERDATA)
End If
End With
End Sub
Da sich die Breite von Panels, bei denen die Eigenschaft AutoSize auf sbrSpring gesetzt ist, ändern kann, brauchen Sie eine Möglichkeit, die Größe eines auf einem solchen Panel platzierten Steuerelements nachzuführen. Sowohl für diesen Fall als auch allgemein für den Fall, dass sich die Größe eines Panels oder der StatusBar selbst ändern sollte, können Sie die Größe eines Steuerelement mit der Prozedur AdjustControlToPanel jederzeit an das zugehörige Panel anpassen. Die Parameter sind die gleichen wie bei der Funktion SetPanelControl.
Public Sub AdjustControlToPanel(Control As Control, _
StatusBar As StatusBar, PanelKey As Variant, _
Optional ByVal AdjustStatusBarToControl As Boolean)
Dim nParent As Object
Dim nPanel As Panel
If IsObject(PanelKey) Then
If TypeOf PanelKey Is Panel Then
Set nPanel = PanelKey
Else
'Error
End If
End If
If nPanel Is Nothing Then
On Error Resume Next
Set nPanel = StatusBar.Panels(PanelKey)
If Err.Number Then
'Error
End If
On Error GoTo 0
End If
With Control
If TypeOf .Parent Is MDIForm Then
Set nParent = .Container
Else
Set nParent = .Parent
End If
End With
zAdjust Control, nParent, nPanel, StatusBar, _
AdjustStatusBarToControl
End Sub
In den allermeisten Fällen gibt es keine Probleme mit den Ereignissen eines Steuerelementen, die in ein StatusBar verschoben worden sind. Sie kommen nach wie vor in den entsprechenden Ereignis-Prozeduren des Steuerelements an. Doch verschieben Sie beispielsweise einen simplen CommandButton, wird dessen Click-Ereignis seltsamerweise nicht mehr ausgelöst. In solchen Fällen verschieben Sie nicht das Steuerelement selbst, sondern verwenden eine PictureBox als Container, auf dem erst das Steuerelement platziert wird, und verschieben diese PictureBox in die StatusBar. Die Positionierung des Steuerelements und seine Anpassung an die Größe der PictureBox können Sie dann bequem im Resize-Ereignis der PictureBox vornehmen. Damit dieser kleine Trick nicht auffällt, setzen Sie die BorderStyle-Eigenschaft der PictureBox auf 0. Und damit die Tab-Reihenfolge nicht durcheinander gerät, sollten Sie die TabStop-Eigenschaft der PictureBox auf False setzen.
|