|
Ein Klick in ein ProgressBar-Steuerelement aus den Microsoft
Common Controls (nur Version 6) - und schon entspricht
der dargestellte Wert der angeklickten Position. Die einzige
Schwierigkeit besteht darin, die Mauszeigerposition in den
entsprechenden Wert innerhalb der von der Min- und der
Max-Eigenschaft liegenden Grenzen umzurechnen. Dann noch einen
Schieberegler-Knopf an diese Position setzen - fertig ist der
Schieberegler mit innenliegender Skalensäule. Wie Sie letztere
farbenfroher gestalten können, zeigen wir Ihnen in "Fortschrittliche
Farben".
Das Modul zu diesem Artikel enthält eine Reihe von Funktionen
zur Umrechnung von Koordinaten in den Wert und umgekehrt, und zum
passgenauen Positionieren eines Objekts, das den Schieberegler-Knopf
darstellen soll.
Der wesentliche Kniff, auf dem alle diese Funktionen beruhen, ist
die Ermittlung des inneren Rechtecks des ProgressBar-Steuerelements,
das die Kontur der Skalensäule umschließt. Dieses Rechteck ist ein
wenig kleiner, als das Gesamtrechteck des Steuerelements. Die
API-Funktion GetClientRect
liefert uns dieses Rechteck in der Maßeinheit Pixels.
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
Je nach Ausrichtung der ProgressBar (Eigenschaft Orientation)
brauchen wir nur die X- oder Y-Koordinate bzw. die Breite oder Höhe
zu berücksichtigen. Bei der vertikalen Ausrichtung ist dazu noch zu
berücksichtigen, dass der Y-Nullpunkt des Koordinatensystems oben
liegt, während die Darstellung der Skalensäule unten beginnt.
Außerdem gibt es noch minimale Abweichungen in der Logik, wie das
Steuerelement das innere Rechteck positioniert - diese sind recht
einfach nach ein paar wenigen Versuchen ermittelt und in die
Berechnungen einbezogen.
Die Funktion ProgressBarMouseValue liefert den einer Mausposition
(X- und Y-Koordinaten) entsprechenden Wert, ohne ihn jedoch zu
setzen.
Public Function ProgressBarMouseValue(ProgressBar As ProgressBar, _
ByVal X As Single, ByVal Y As Single) As Single
Dim nRect As RECT
Dim nRange As Long
Dim nMouseValue As Double
With ProgressBar
GetClientRect .hwnd, nRect
nRange = .Max - .Min
Select Case .Orientation
Case ccOrientationHorizontal
With nRect
nMouseValue = ((X / Screen.TwipsPerPixelX) * nRange) / _
(.Right - .Left - 2)
End With
Case ccOrientationVertical
nMouseValue = .Max - (((Y / Screen.TwipsPerPixelY) - 1) _
* nRange) / (nRect.Bottom - nRect.Top - 2)
End Select
Select Case nMouseValue
Case Is < .Min
ProgressBarMouseValue = .Min
Case Is > .Max
ProgressBarMouseValue = .Max
Case Else
ProgressBarMouseValue = nMouseValue
End Select
End With
End Function
Im Prinzip die Umkehrung dazu ist die Funktion
ProgressBarValueToSize. Sie liest den aktuellen Wert der ProgressBar
aus und gibt die Entfernung in Twips zurück - bei horizontaler
Ausrichtung von links gesehen, bei vertikaler Ausrichtung von oben
gesehen.
Public Function ProgressBarValueToSize(ProgressBar As ProgressBar) _
As Single
Dim nRect As RECT
Dim nRange As Long
With ProgressBar
GetClientRect .hwnd, nRect
nRange = .Max - .Min
Select Case .Orientation
Case ccOrientationHorizontal
ProgressBarValueToSize = (((nRect.Right - nRect.Left - 2) _
* .Value / nRange) + 3) * Screen.TwipsPerPixelX
Case ccOrientationVertical
ProgressBarValueToSize = _
.Height - (((nRect.Bottom - nRect.Top - 2) _
* .Value / nRange) + 3) * Screen.TwipsPerPixelY
End Select
End With
End Function
Anhand des Rückgabewerts der vorangegangenen Funktion könnten
Sie nun in Schiebeknopf-Objekt positionieren. Die folgende Prozedur
ProgressBarSetSliderToValue erledigt das gleich in einem Aufruf. Sie
brauchen lediglich das betreffende Objekt zu übergeben. Dies kann
eine Schaltfläche sein, aber auch jedes andere Objekt, das über
die Eigenschaften Left, Top und Height verfügt.
Public Sub ProgressBarSetSliderToValue(ProgressBar As ProgressBar, _
Slider As Object)
Dim nRect As RECT
Dim nRange As Long
Dim nSize As Single
With ProgressBar
GetClientRect .hwnd, nRect
nRange = .Max - .Min
Select Case .Orientation
Case ccOrientationHorizontal
nSize = (((nRect.Right - nRect.Left - 2) * .Value / _
nRange) + 3) * Screen.TwipsPerPixelX
Slider.Left = .Left + nSize - (Slider.Width \ 2)
Case ccOrientationVertical
nSize = (((nRect.Bottom - nRect.Top - 2) * .Value / _
nRange) + 3) * Screen.TwipsPerPixelY
Slider.Top = .Top + .Height - nSize - _
(Slider.Height \ 2)
End Select
End With
End Sub
Den eigentlichen Schieberegler-Effekt bietet schließlich die
Prozedur ProgressBarSetSliderToPosition. Ihr übergeben Sie das
Schiebeknopf-Objekt, die X- und Y-Koordinaten (die Sie etwa von den
Mausereignissen geliefert bekommen). Die ProgressBar wird
automatisch auf den der Position entsprechenden Wert gesetzt, und
der Schiebeknopf wird passend positioniert. Dabei wird auch dafür
gesorgt, dass der Schiebeknopf nicht über die Endpositionen
hinausrutschen kann. Optional können Sie noch eine Schrittweite
angeben - der Schiebeknopf (und natürlich auch der Wert) scheint an
den entsprechenden Teilungen "einzurasten".
Public Sub ProgressBarSetSliderToPosition(ProgressBar As ProgressBar, _
Slider As Object, ByVal X As Single, ByVal Y As Single, _
Optional ByVal Step As Long)
Dim nRect As RECT
Dim nRange As Long
Dim nSize As Single
Dim nValue As Double
Dim nSteps As Long
Dim nRectSize As Double
Dim nLeftTop As Single
With ProgressBar
GetClientRect .hwnd, nRect
nRange = .Max - .Min
Select Case .Orientation
Case ccOrientationHorizontal
With nRect
nRectSize = .Right - .Left - 2
End With
nValue = ((X / Screen.TwipsPerPixelX) * nRange) / nRectSize
Select Case nValue
Case Is < .Min
nValue = .Min
Case Is > .Max
nValue = .Max
End Select
If Step > 0 Then
nValue = (nValue \ Step) * Step
End If
.Value = nValue
nSize = (nRectSize * nValue / nRange) _
* Screen.TwipsPerPixelX
nLeftTop = .Top
With Slider
.Left = nLeftTop + nSize - (.Width \ 2) - 2 _
* Screen.TwipsPerPixelX
End With
Case ccOrientationVertical
With nRect
nRectSize = .Bottom - .Top - 2
End With
nValue = ((((.Height - Y) / Screen.TwipsPerPixelY) - 5) _
* nRange) / nRectSize
Select Case nValue
Case Is < .Min
nValue = .Min
Case Is > .Max
nValue = .Max
End Select
If Step > 0 Then
nValue = (nValue \ Step) * Step
End If
.Value = nValue
nSize = (nRectSize * nValue / nRange) _
* Screen.TwipsPerPixelY
nLeftTop = .Top + .Height
With Slider
.Top = nLeftTop - nSize - (.Height \ 2) - 3 _
* Screen.TwipsPerPixelY
End With
End Select
End With
End Sub
Die Eigenschaft Enabled des Schiebeknopf-Objekts sollten Sie auf
False setzen, damit die die dahinter liegende ProgressBar die
Mausereignisse empfangen kann.
|