ABOUT Visual Basic Programmieren Programmierung Download Downloads Tips & Tricks Tipps & Tricks Know-How Praxis VB VBA Visual Basic for Applications VBS VBScript Scripting Windows ActiveX COM OLE API ComputerPC Microsoft Office Microsoft Office 97 Office 2000 Access Word Winword Excel Outlook Addins ASP Active Server Pages COMAddIns ActiveX-Controls OCX UserControl UserDocument Komponenten DLL EXE
Diese Seite wurde zuletzt aktualisiert am 11.07.2001

Diese Seite wurde zuletzt aktualisiert am 11.07.2001
Aktuell im ABOUT Visual Basic-MagazinGrundlagenwissen und TechnologienKnow How, Tipps und Tricks rund um Visual BasicAddIns für die Visual Basic-IDE und die VBA-IDEVBA-Programmierung in MS-Office und anderen AnwendungenScripting-Praxis für den Windows Scripting Host und das Scripting-ControlTools, Komponenten und Dienstleistungen des MarktesRessourcen für Programmierer (Bücher, Job-Börse)Dies&Das...

Themen und Stichwörter im ABOUT Visual Basic-Magazin
Code, Beispiele, Komponenten, Tools im Überblick, Shareware, Freeware
Ihre Service-Seite, Termine, Job-Börse
Melden Sie sich an, um in den vollen Genuss des ABOUT Visual Basic-Magazins zu kommen!
Informationen zur AVB-Web-Site, Kontakt und Impressum

Zurück...

Astronomischer Spin

Zurück...

(-hg) mailto:hg_updownex@aboutvb.de

Das UpDown-Steuerelement aus den Microsoft Common Controls 2 ermöglicht nur ganzzahlige Werte, Schrittweiten und Unter- und Obergrenzen. Wie wäre es dagegen mit einem Steuerelement dieser Art (auch "Spin"-Steuerelemente genannt), dessen Wert, Schrittweite und Grenzen beliebige Werte des Datentyps Decimal sein können? Decimal ist ein Unterdatentyp von Variant und kann extrem große Werte von bis zu 29 Stellen vor dem Komma oder extrem kleine Werte bis zu 28 Stellen nach dem Komma annehmen.

Der Trick ist eigentlich ganz einfach. Sie nehmen eine vertikale Scrollbar und bringen sie auf die Höhe etwa einer TextBox. Damit entspricht ihr Aussehen schon mal dem des UpDown-Steuerelements. Dann setzen Sie als Min-Wert -1, als Max-Wert 1, als SmallChange 1 und als Value 0. LargeChange bleibt unberührt auf 1, da die große Schrittweite bei einer so geschrumpften Scrollbar sowieso nicht zum Tragen kommt. Für den aktuellen Wert, die Schrittweite und die Grenzen deklarieren Sie separate Variant-Variablen. Im Change-Ereignis der Scrollbar prüfen Sie nun nur noch das Vorzeichen der Value-Eigenschaft über die Sgn-Funktion. Ist es positiv (Sgn liefert 1), addieren Sie die Schrittweite zum aktuellen Wert, ist es negativ (Sgn liefert -1), subtrahieren Sie die Schrittweite. Die Value-Eigenschaft der Scrollbar setzen Sie sogleich wieder auf 0. Zwar wird dadurch erneut das Change-Ereignis ausgelöst. Doch ja Sgn nun 0 zurückgibt, ignorieren Sie diese Auslösung. Dieses ständige Umschalten des Wertes der Scrollbar zwischen 0 und +1 bzw. -1 funktioniert auch einwandfrei bei Dauerfeuer - wenn der Anwender die Maustaste auf einer der beiden Scrollflächen niedergedrückt lässt.

Natürlich müssen Sie dazu noch prüfen, ob der neu berechnete Wert die Grenzen unter- bzw. überschreitet und ihn gegebenenfalls auf den unteren oder oberen Grenzwert beschränken. Auch sind Prüfungen sinnvoll, ob ein neu gesetzter Max-Wert tatäschlich größer als der Min-Wert ist, und ob auch nach der Änderung einer der Grenzen der aktuelle Wert noch innerhalb derselben liegt. Auch ergibt es keinen Sinn, eine Schrittweite zu setzen, die größer als die Differenz zwischen Ober- und Untergrenze wäre. Und wenn Sie dann den Wert auch noch formatiert ausgeben möchten...

...ist das Grund genug, ein eigenständiges Steuerelement auf der Basis eines UserControls zu entwickeln und alle diese Berechnungen und Prüfungen darin zu verpacken. Nun ist es auch ein Leichtes, noch ein paar praktische Features hinzuzufügen.

So ist die Frage durchaus bedenkenswert, welchen Wert unser Steuerelement annehmen soll, wenn bei "krummen" Schrittweiten die Grenzen überschritten würden. Soll der Wert dann auf die jeweilige Grenze gesetzt werden? Oder soll der letzte Wert beibehalten werden? Die Eigenschaften MinBoundary und MaxBoundary legen dies fest. Sind sie auf True gesetzt, wird der Wert auf die Grenze gesetzt.

Ein weiteres Feature, das wir gleich und ohne Aufwand einfügen können, ist die Ausgabe des Wertes als formatierter Text. Während die Eigenschaft Value immer den Variant-Wert zurückgibt, liefert die Eigenschaft ValueFormat den Wert in dem Format, das in der Eigenschaft Format angegeben ist. Ist dort nur ein leerer String angegeben, gibt auch ValueFormat den Wert unformatiert zurück, allerdings als Variant-Datentyp String. Als Format können Sie alle Formatierungs-Strings und benannten Formate angeben, die auch in der Standard-Format-Funktion in VB/VBA möglich sind.

Jede Änderung des Wertes wird über das Ereignis Change (das einzige Ereignis des Steuerelements) gemeldet. Der Einfachheit halber übergibt es im Parameter Value gleich den aktuellen Wert. Ist die Eigenschaft FormattedEvent gesetzt, enthält der Parameter den entsprechend der Format-Eigenschaft formatierten Wert als String, ansonsten den Variant-Wert.

Natürlich können Sie jederzeit die Value-Eigenschaft auf einen beliebigen Wert setzen. Sie können die Erhöhung oder Verminderung des Wertes aber auch über die Methoden Incr und Decr vornehmen und dabei die Anzahl der Schritte optional übergeben (Voreinstellung ist 1).

Public Event Change(Value As Variant)

Private pFormat As String
Private pFormattedEvent As Boolean
Private pMax As Variant
Private pMaxBoundary As Boolean
Private pMin As Variant
Private pMinBoundary As Boolean
Private pStep As Variant
Private pValue As Variant

Public Property Get Format() As String
  Format = pFormat
End Property

Public Property Let Format(New_Format As String)
  Dim nValueFormat As String
  
  If pFormat <> New_Format Then
    pFormat = New_Format
    On Error Resume Next
    nValueFormat = Me.ValueFormat
    If Err.Number Then
      On Error GoTo 0
      Err.Raise 380
    Else
      PropertyChanged "Format"
    End If
    zRaiseEvent
  End If
End Property

Public Property Get FormattedEvent() As Boolean
  FormattedEvent = pFormattedEvent
End Property

Public Property Let FormattedEvent(New_FormattedEvent As Boolean)
  If pFormattedEvent <> New_FormattedEvent Then
    pFormattedEvent = New_FormattedEvent
    zRaiseEvent
    PropertyChanged "FormattedEvent"
  End If
End Property

Public Property Get MaxBoundary() As Boolean
  MaxBoundary = pMaxBoundary
End Property

Public Property Let MaxBoundary(New_MaxBoundary As Boolean)
  pMaxBoundary = New_MaxBoundary
  PropertyChanged "MaxBoundary"
End Property

Public Property Get Max() As Variant
  Max = pMax
End Property

Public Property Let Max(Max As Variant)
  Dim nMax As Variant
  
  On Error Resume Next
  nMax = CDec(Max)
  If Err.Number Then
    On Error GoTo 0
    Err.Raise 380
  ElseIf pMax <> nMax Then
    pMax = nMax
    If pValue > pMax Then
      Me.Value = pMax
    End If
    If pMax < pMin Then
      pMax = pMin
      Err.Raise 380
    End If
    PropertyChanged "Max"
  End If
End Property

Public Property Get Min() As Variant
  Min = pMin
End Property

Public Property Let Min(Min As Variant)
  Dim nMin As Variant
  
  On Error Resume Next
  nMin = CDec(Min)
  If Err.Number Then
    On Error GoTo 0
    Err.Raise 380
  ElseIf pMin <> nMin Then
    pMin = nMin
    If pValue < pMin Then
      Me.Value = pMin
    End If
    If pMin > pMax Then
      pMin = pMax
      Err.Raise 380
    End If
    PropertyChanged "Min"
  End If
End Property

Public Property Get MinBoundary() As Boolean
  MinBoundary = pMinBoundary
End Property

Public Property Let MinBoundary(New_MinBoundary As Boolean)
  pMinBoundary = New_MinBoundary
  PropertyChanged "MinBoundary"
End Property

Public Property Get Step() As Variant
  Step = pStep
End Property

Public Property Let Step(Step As Variant)
  Dim nStep As Variant
  
  On Error Resume Next
  nStep = CDec(Step)
  If Err.Number Then
    On Error GoTo 0
    Err.Raise 380
  Else
    If nStep <= 0 Then
      Err.Raise 380
    Else
      pStep = nStep
      If pStep > (pMax - pMin) Then
        pStep = pMax - pMin
        Err.Raise 380
      End If
      PropertyChanged "Step"
    End If
  End If
End Property

Public Property Get Value() As Variant
  Value = pValue
End Property

Public Property Let Value(Value As Variant)
  Dim nValue As Variant
  Dim nOldValue As Variant
  
  On Error Resume Next
  nValue = CDec(Value)
  If Err.Number Then
    On Error GoTo 0
    Err.Raise 380
  ElseIf pValue <> nValue Then
    nOldValue = pValue
    pValue = nValue
    Select Case pValue
      Case Is < pMin
        If pMinBoundary Then
          pValue = pMin
        Else
          pValue = pValue + pStep
        End If
      Case Is > pMax
        If pMaxBoundary Then
          pValue = pMax
        Else
          pValue = pValue - pStep
        End If
    End Select
    If pValue <> nOldValue Then
      zRaiseEvent
      PropertyChanged "Value"
    End If
  End If
End Property

Public Property Get ValueFormat() As String
  If Len(pFormat) Then
    On Error Resume Next
    ValueFormat = VBA.Format$(pValue, pFormat)
  Else
    ValueFormat = CStr(pValue)
  End If
End Property
  
Public Sub Decr(Optional ByVal Steps As Long = 1)
  Select Case Steps
    Case Is > 0
      Me.Value = pValue - Steps * pStep
    Case Else
      Err.Raise 5
  End Select
End Sub

Public Sub Incr(Optional ByVal Steps As Long = 1)
  Select Case Steps
    Case Is > 0
      Me.Value = pValue + Steps * pStep
    Case Else
      Err.Raise 5
  End Select
End Sub

Private Sub vs_Change()
  Dim nSgn As Integer
  
  Static sInProc As Boolean
    
  If sInProc Then
    Exit Sub
  Else
    sInProc = True
  End If
  With vs
    nSgn = Sgn(.Value)
    .Value = 0
    On Error Resume Next
    Select Case nSgn
      Case 0
      Case -1
        Me.Value = CDec(pValue) - CDec(pStep)
      Case 1
        Me.Value = CDec(pValue) + CDec(pStep)
    End Select
  End With
  sInProc = False
End Sub

Private Sub UserControl_Resize()
  On Error Resume Next
  With UserControl
    vs.Move 0, 0, .ScaleWidth, .ScaleHeight
  End With
End Sub

Private Sub UserControl_Initialize()
  pMax = 100
  pStep = 1
End Sub

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
  With PropBag
    pFormat = .ReadProperty("Format", "")
    pFormattedEvent = .ReadProperty("FormattedEvent", False)
    pMax = .ReadProperty("Max", 100)
    pMaxBoundary = .ReadProperty("MaxBoundary", False)
    pMin = .ReadProperty("Min", 0)
    pMinBoundary = .ReadProperty("MinBoundary", False)
    pStep = .ReadProperty("Step", 1)
    pValue = .ReadProperty("Value", 0)
  End With
End Sub

Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
  With PropBag
    .WriteProperty "Format", pFormat, ""
    .WriteProperty "FormattedEvent", pFormattedEvent, False
    .WriteProperty "Max", pMax, 100
    .WriteProperty "MaxBoundary", pMaxBoundary, False
    .WriteProperty "Min", pMin, 0
    .WriteProperty "MinBoundary", pMinBoundary, False
    .WriteProperty "Step", pStep, 1
    .WriteProperty "Value", pValue, 0
  End With
End Sub

Private Sub zRaiseEvent()
  If pFormattedEvent Then
    RaiseEvent Change(Me.ValueFormat)
  Else
    RaiseEvent Change(pValue)
  End If
End Sub

Das Projekt avbUpDownEx (updownex.zip - ca. 8,2 KB)



Komponenten-Übersicht

Schnellsuche




Zum Seitenanfang

Copyright © 1999 - 2023 Harald M. Genauck, ip-pro gmbh  /  Impressum

Zum Seitenanfang

Zurück...

Zurück...