Eine Internet-Seite ohne Laufschrift sei keine richtige Internet-Seite, sagen manche Leute. Wenn das wahr sein sollte, dann würde ich einfach behaupten, ein Visual Basic-Programm ohne Laufschrift-Tooltips sei kein richtiges Visual Basic-Programm. Wie, Laufschrift-Tooltips? Sie haben noch nie etwas davon gehört? Ich bis vorhin auch nicht. Und natürlich sähe ich genauso wenig einen Sinn dafür in einem seriösen VB-Programm wie etwa in einer seriösen Internet-Seite. Aber es geht - und darum habe ich das eben einfach mal gemacht.
Das Prinzip ist recht einfach. Es handelt sich um ein UserControl, das wie ein Timer zur Laufzeit unsichtbar bleibt und seine Dienste zur Verfügung stellt. Ihm wird das Control zugewiesen, dessen ToolTip-Text zur animierten Laufschrift werden soll. Der ToolTip-Text und Steuerparameter sind als Eigenschaften des Controls implementiert.
Für die Bewegung der Laufschrift sorgt ein Timer. Deswegen hat das avbMarqueeToolTip-Control auch die bekannten Timer-Eigenschaften Enabled und Interval. Letztere bestimmt in erster Linie das Tempo der Laufschrift. Die Intervall-Einheit beträgt entsprechend dem Timer eine Tausendstel Sekunde und der Wertebereich erstreckt sich von 0 bis 65.535.
Public Property Get Enabled() As Boolean
Enabled = pEnabled
End Property
Public Property Let Enabled(ByVal New_Enabled As Boolean)
pEnabled = New_Enabled
If Ambient.UserMode Then
zEnableTimer
End If
PropertyChanged "Enabled"
End Property
Public Property Get Interval() As Long
Interval = tmr.Interval
End Property
Public Property Let Interval(ByVal New_Interval As Long)
Select Case Interval
Case 0 To 65535
tmr.Interval = New_Interval
zEnableTimer
Case Else
Err.Raise 380
End Select
PropertyChanged "Interval"
End Property
Das Tempo wird aber auch von der Eigenschaft StepWidth mit dem Mindestwert 1 mitbestimmt. Sie legt fest, um wie viele Zeichen der angezeigte Text bei jedem Schritt verschoben wird. Je höher dieser Wert, um so schneller scheint die Schrift zu laufen - eine flüssig erscheinende Bewegung ergibt sich jedoch nur bei kleinen Timer-Intervallen. Ist der StepWidth-Wert im Verhältnis zur Gesamtlänge des Textes zu hoch, kann sogar der Eindruck entstehen, der Text liefe in die Gegenrichtung oder die Richtung wechsele ständig und mehr oder weniger unregelmäßig.
Public Property Get StepWidth() As Integer
StepWidth = pStepWidth
End Property
Public Property Let StepWidth(ByVal New_StepWidth As Integer)
Select Case New_StepWidth
Case 1 To Len(pText) - 1
pStepWidth = New_StepWidth
Case Else
Err.Raise 380
End Select
PropertyChanged "StepWidth"
End Property
Die Lauf- und Leserichtung wird über die Eigenschaft Direction festgelegt. Für Sie ist ein enumerierter Datentyp definiert, mtDirectionConstants. Ich hätte zwar auch Boolean als Datentyp wählen können und vorwärts als True und nicht-vorwärts, also rückwärts, als False festlegen können - aber auch genau umgekehrt. Bei Eigenschaften, die zwar zwei gegensinnig wirkende Werte darstellen sollen, wobei aber keiner von beiden im eigentlichen Sinne als wahr oder falsch anzusehen ist, sollten Sie besser einen enumerierten Datentyp verwenden. Sie können den Eigenschaftencharakter durch entsprechende Namenswahl der Konstanten wesentlich besser repräsentieren. Im Prinzip sind enumerierte Datentypen auch nichts anderes als numerische Werte, haben aber den Vorteil, dass deren Bedeutung über den Konstantennamen wesentlich einfacher zu merken ist, als etwa über schlichte Zahlen - wie in diesem Fall den Werten 0 und 1. Außerdem haben enumerierte Datentypen den Vorteil, dass Sie sich im Eigenschaftenfenster durch die Auswahl einfach hindurchklicken können (Doppelklick auf die Beschriftung oder auf die Auswahl-ComboBox), bis Sie den gewünschten Wert gefunden haben. Voreingestellt ist übrigens die Laufrichtung von links nach rechts - das entspricht unseren europäischen Lesegewohnheiten.
Public Enum mtDirectionConstants
mtLeftToRight
mtRightToLeft
End Enum
Public Property Get Direction() As mtDirectionConstants
Direction = pDirection
End Property
Public Property Let Direction(ByVal New_Direction _
As mtDirectionConstants)
Select Case New_Direction
Case pDirection
Case mtLeftToRight, mtRightToLeft
pDirection = New_Direction
Case Else
Err.Raise 380
End Select
PropertyChanged "Direction"
End Property
Die Länge des als Tooltip angezeigten Textabschnitts legen Sie in der Eigenschaft ShowedLength fest. Ist ihr Wert 0 oder größer als die Textlänge selbst, wird der gesamte Text als Tooltip angezeigt. Diese Anzeigelänge beeinflusst ebenfalls die Wirkung der Laufschrift im Zusammenspiel mit dem StepWidth-Wert.
Public Property Get ShowedLength() As Integer
ShowedLength = pShowedLength
End Property
Public Property Let ShowedLength(ByVal New_ShowedLength As Integer)
If New_ShowedLength >= 0 Then
pShowedLength = New_ShowedLength
Else
Err.Raise 380
End If
PropertyChanged "ShowedLength"
End Property
Zu guter Letzt wird der anzuzeigende Tooltip-Inhalt in der Eigenschaft Text festgelegt. Ist die Laufschrift nicht aktiviert (Enabled = False), wird der in ShowLength festgelegte Ausschnitt vom Textanfang her wie ein gewöhnlicher Tooltip stillstehend angezeigt.
Public Property Get Text() As String
Text = pText
End Property
Public Property Let Text(New_Text As String)
If pText <> New_Text Then
pText = New_Text
mToolTipText = pText
zEnableTimer
End If
PropertyChanged "Text"
End Property
Alle diese Eigenschaften können Sie zur Designzeit im Eigenschaftenfenster festlegen. Die Festlegung, welches Steuerelement den laufenden Tooltip anzeigen soll, wird zur Laufzeit über die Eigenschaft CtlToolTip festgelegt (in der Regel am besten im Form_Load-Ereignis). Dieser können Sie jedes beliebige Steuerelement (genau genommen eine Referenz darauf) per Set-Anweisung zuweisen, wenn es über die Eigenschaft ToolTipText verfügt. Im Prinzip verfügen die meisten der in der Werkzeugsammlung auftauchenden Steuerelemente über diese Eigenschaft, wenn sie zur Laufzeit sichtbar sind. Der Timer beispielsweise und ebenso dieses Laufschrift-Control sind es nicht, verfügen also auch nicht über diese Eigenschaft. In der Property Set-Prozedur CtlToolTip wird das Vorhandensein der ToolTipText-Eigenschaft über eine OnError Resume Next-Fehlerbehandlung bei der erstmaligen Zuweisung des ToolTip-Textes zwangsweise ausgetestet. Ist sie nicht vorhanden, wird die interne, zur Speicherung der Steuerelement-Referenz dienende Variable pCtlToolTip auf Nothing gesetzt, der Timer in jedem Fall deaktiviert und ein Fehler Nr. 380 ausgelöst. Dieser Fehler bedeutet, dass versucht wurde, der Eigenschaft einen ungültigen bzw. unzulässigen Wert zuzuweisen - was ein Steuerelement ohne ToolTipText in diesem Sinne ja auch wäre.
Public Property Get CtlToolTip() As Object
Set CtlToolTip = pCtlToolTip
End Property
Public Property Set CtlToolTip(New_CtlToolTip As Object)
Set pCtlToolTip = New_CtlToolTip
If Not (pCtlToolTip Is Nothing) Then
On Error Resume Next
Select Case pShowedLength
Case 0, Is > Len(pText)
pCtlToolTip.ToolTipText = pText
Case Else
pCtlToolTip.ToolTipText = Left$(pText, pShowedLength)
End Select
If Err.Number Then
Set pCtlToolTip = Nothing
tmr.Enabled = False
Err.Raise 380
Else
On Error GoTo 0
zEnableTimer
End If
End If
End Property
Bei jeder Änderung einer der Eigenschaften, von denen abhängt, ob der Timer - und damit die Laufschrift - aktiv sein sollen, wird die private Prozedur zEnableTimer aufgerufen. Hier wird geprüft, ob ein Steuerelement zugewiesen ist, ob das Interval größer als 0 ist und ob der anzuzeigende Text überhaupt eine Länge hat bzw. länger als ein Zeichen ist. Nur dann wird der Timer aktiviert. Anderenfalls wären die Aktivierung des Timers und die Ausführung der Timer-Ereignisprozedur sinnlos, da sowieso kein Tooltip angezeigt werden würde.
Private Sub zEnableTimer()
With tmr
If pCtlToolTip Is Nothing Then
.Enabled = False
Else
On Error Resume Next
Select Case pShowedLength
Case 0, Is >= Len(mToolTipText)
pCtlToolTip.ToolTipText = mToolTipText
Case Else
pCtlToolTip.ToolTipText = Left$(mToolTipText, _
pShowedLength)
End Select
If .Interval = 0 Then
.Enabled = False
Else
If Len(pText) > 1 Then
.Enabled = pEnabled
Else
.Enabled = False
End If
End If
End If
End With
End Sub
Wie schließlich das Erscheinungsbild und die fixe Größe des Controls zur Designzeit zustande kommen, finden Sie in "Mehr scheinen als sein" näher erläutert.
Wird zur Laufzeit das Timer-Ereignis ausgelöst, wird zunächst der Tooltip-Text (dessen aktueller Zustand intern in der modulweit gültigen Variablen mToolTipText zwischengespeichert wird) entsprechend der Laufrichtung und der Schrittweite umgestellt. Dann wird die Länge des anzuzeigenden Ausschnitts ermittelt und schließlich dieser Ausschnitt bzw. gegebenenfalls der gesamte Text der ToolTipText-Eigenschaft des referenzierten Steuerelements zugewiesen (das geschieht im Code des Controls - Sie brauchen dafür keine Extra-Zeile Code zu schreiben). Und das war es dann auch schon - der Tooltip wird dann immer im aktualisierten Zustand angezeigt, wenn sich der Mauszeiger über dem Steuerelement befindet.
Nun noch zu erwähnen bleibt die Methode Reset, als einzige des Controls. Über Ihren Aufruf können Sie den umlaufenden ToolTip-Text wieder in seinen Anfangzustand zurückversetzen.
Public Sub Reset()
If Not (pCtlToolTip Is Nothing) Then
mToolTipText = pText
End If
End Sub
Hmmmm... so im zusammenfassenden Rückblick denke ich, dass dieses Control gar nicht so sinnlos ist. Ich finde, ich vermittele Ihnen darin eine ganze Reihe interessanter Tipps zu Vorgehensweisen und zur sauberen UserControl-Programmierung. Ich überlege gerade nur noch, ob ich nicht im Beispiel-Programm die komplette Visual Basic-Dokumentation in die Text-Eigenschaft des Controls stopfen soll. Schließlich enthält die VB-Dokumentation auch eine ganze Menge Wissenswertes, was man sonst gar so schnell überliest. Sie müssten dann lediglich lange genug die Laufschrift an Ihren Augen vorbeiziehen lassen und den Mauszeiger nicht von der Stelle rühren, um mit Sicherheit alle relevanten Stellen gesehen zu haben und sich nichts entgehen zu lassen... Na, wäre das nicht ein hypercooler Top-Verwendungszweck - nicht nur kurze Hinweise, sondern ganze Handbücher, ach was, ganze Bibliotheken in dauerlaufenden Tooltips?
|