Neulich ärgerte ich mich mal wieder über die fehlende Ergonomie einer meiner Datenbanken. Dort bewege ich mich in einem Detailformular öfter mal ein paar hundert Datensätze vor oder zurück. Das geht entweder per Navigationsschaltflächen (wenn der gesuchte Datensatz in der Nähe liegt) oder per Filter über die Datensatz-ID. Eine elegantere Lösung wäre eine Art Datensatz-Bildlaufleiste, mit der man den Datensatzzeiger schneller vor- und zurückspringen lassen kann. Schauen wir also, ob sich das mit Access realisieren lässt.
Der Datensatz-Slider soll nicht nur als Eingabe-Steuerelement dienen, sondern auch reagieren, wenn Sie die Position des Datensatzzeigers anderweitig verändern – also auch beim Löschen oder Hinzufügen von Datensätzen. Das Steuerelement soll etwa so wie in Bild 1 aussehen.
Bild 1: Der Datensatz-Slider in einem Beispielformular
Den Slider bauen Sie selbst zusammen, indem Sie ein Rechteck-Steuerelement als Hintergrund und eine Schaltfläche als Slider einsetzen. Die grafische Gestaltung bleibt Ihnen überlassen – allein bezüglich der Breite des Hintergrund-Rechtecks gibt es keinen Spielraum: Der gibt genau vor, von wo bis wo der Benutzer den Slider bewegen kann.
Mausbewegungen nutzen
Als Erstes soll der Slider als Eingabe-Steuerelement dienen, also beim Bewegen die Position des Datensatzzeigers und somit den aktuell angezeigten Datensatz verändern. Dies erreichen Sie durch das Anklicken der Schaltfläche und durch anschließendes Bewegen des Mauszeigers bei gedrückter linker Maustaste. Dabei sind einige Regeln wichtig: Wenn der Mauszeiger nach dem ersten Anklicken über oder unter die Schaltfläche rutscht, soll diese einfach weiter nach links oder rechts bewegt werden können. Wenn die Schaltfläche ganz nach links verschoben wurde und der Benutzer den Mauszeiger weiter nach links bewegt, soll der Slider natürlich stehen bleiben. Erst wenn der Benutzer die Maus wieder nach rechts bewegt, soll sich der Slider mit nach rechts bewegen – allerdings erst, wenn der Mauszeiger sich wieder auf der gleichen Breite wie die Schaltfläche befindet. Das Gleiche gilt für die rechte Seite.
Maus-Ereignisse
Das Schaltflächen-Steuerelement, das Sie hier als Slider verwenden werden, löst drei Ereignisse aus, die wir hier gut gebrauchen können: Bei Maustaste ab reagiert auf das Betätigen einer der Maustasten, Bei Maustaste auf wird ausgelöst, wenn die Maustaste wieder losgelassen wird.
Dabei gilt: Das Anklicken der Maustaste muss auf dem Steuerelement erfolgen, das Loslassen kann an beliebiger Stelle geschehen. Wenn der Benutzer den Mauszeiger über der Schaltfläche bewegt, wird für jede Bewegung in einem bestimmten Intervall das Ereignis Bei Mausbewegung ausgelöst. Dabei liefert der Parameter X jeweils die X-Position des Mauszeigers vom linken Rand des Steuerelements.
Schaltfläche verschieben
Um die Schaltfläche bei gedrückter Maustaste zu verschieben, muss die Ereignisprozedur, die durch das Ereignis Bei Mausbewegung ausgelöst wird, zunächst erkennen, ob die linke Maustaste gerade heruntergedrückt ist. Ist dies der Fall, soll die Schaltfläche jeweils um die gleiche Entfernung nach links oder rechts bewegt werden, die der Mauszeiger soeben zurückgelegt hat. Die Schaltfläche folgt dem Mauszeiger also mit einer geringen zeitlichen Verzögerung. Das gelingt im einfachsten Fall mit zwei einfachen Ereignisprozeduren. Die erste wird beim ersten Herunterdrücken der Maustaste auf dem Slider ausgelöst und speichert die X-Koordinate, auf welcher der Benutzer die Taste gedrückt hat:
Private Sub cmdSlider_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single) sngX = X End Sub
Die zweite wird beim Bewegen des Mauszeigers ausgelöst. Sie prüft, ob der Benutzer gerade die linke Maustaste herunterdrückt. In diesem Fall liefert der Parameter Button den Wert 1. Ist das der Fall, stellt die Prozedur den Abstand des Sliders vom linken Formularrand auf den vorherigen Abstand plus der neuen Position minus der alten Position ein:
Private Sub cmdSlider_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single) If Button = 1 Then cmdSlider.Left = cmdSlider.Left + X - sngX End If End Sub
Auf diese Weise können Sie den Slider nach links und rechts bewegen. Die erste Hürde folgt allerdings sogleich: Der Slider lässt sich nämlich nicht durch den linken und den rechten Rand des Rechteck-Steuerelements aufhalten, das eigentlich als Begrenzung dienen sollte. Also bauen wir eine Bedingung ein, die den Slider nicht aus den vorgegebenen Grenzen herauslässt.
Damit diese Bedingung funktioniert, muss sie bereits vor der Übertragung der Bewegung des Mauszeigers auf den Slider prüfen, ob der Slider sich über den linken oder rechten Rand des Rechteck-Steuerelements hinausbewegen würde.
Dazu berechnen wir in einer einfachen Anweisung die nächste Position, speichern diese in einer Variablen und prüfen dann, ob der linke oder rechte Rand übertreten würde:
Dim sngNewX As Single If Button = 1 Then sngNewX = Me!cmdSlider.Left + X - sngX If sngNewX >= Me!rctFrame.Left And sngNewX + Me.cmdSlider.Width <= _ Me.rctFrame.Left + Me.rctFrame.Width Then Me!cmdSlider.Left = Me!cmdSlider.Left + X - sngX End If End If
Auf diese Weise erhalten wir bereits das gewünschte Verhalten des Sliders: Wenn der Mauszeiger links oder rechts über den durch das Rechteck-Steuerelement festgelegten Bereich hinausfährt, bleibt die Slider-Schaltfläche stehen. Und wir erhalten noch ein weiteres Verhalten gratis dazu: Wenn der Mauszeiger zum Slider zurückbewegt wird, bewegt er diesen bei gedrückter Maustaste einfach weiter, als ob nichts gewesen wäre.
Datensatzzeiger bewegen
Nun sorgen Sie dafür, dass der Datensatzzeiger analog zum Slider bewegt wird. Das heißt, dass er auf der Position ganz links den ersten Datensatz markiert und auf der Position ganz rechts den letzten Datensatz. Dazu müssen Sie die Position des Sliders in eine entsprechende Position des Datensatzzeigers umrechnen. Dazu nehmen wir erstmal einige Vereinfachungen vor, die sich im Nachhinein auf die Performance auswirken werden: Die Prozedur soll nicht bei jedem Aufruf erneut die Position und Breite der beiden Steuerelemente rctFrame und cmdSlider ermitteln.
Daher speichern wir alle fixen Werte beim Öffnen des Formulars in entsprechenden Variablen. Deren Deklaration sieht so aus:
Dim sngFrameWidth As Single Dim sngSliderWidth As Single Dim sngFrameLeft As Single Dim sngRange As Single
Diese Variablen werden beim Öffnen des Formulars wie folgt gefüllt:
Private Sub Form_Open(Cancel As Integer) sngFrameWidth = Me!rctFrame.Width sngSliderWidth = Me!cmdSlider.Width sngFrameLeft = Me!rctFrame.Left sngRange = sngFrameWidth - sngSliderWidth End Sub
In die Prozedur, die beim Bewegen der Maus ausgelöst wird, fügen wir als ersten Ansatz die folgende Zeile ein:
Me.Recordset.AbsolutePosition = Me.Recordset.RecordCount * (Me!cmdSlider.Left - sngFrameLeft) / (sngRange)
Diese ermittelt über die RecordCount-Eigenschaft des Recordset-Objekts des Formulars die Datensatzanzahl und multipliziert diese anschließend mit einem Faktor, welcher der Position des Sliders innerhalb des Rechtecks entspricht. Diese ermitteln wir aus dem Quotienten der tatsächlichen Position (Abstand Slider vom linken Rand minus Abstand Rechteck vom linken Rand) und der Breite des Bereichs, in dem man den Slider bewegen kann (Breite des Rechtecks minus Breite des Sliders – wird bereits beim Öffnen des Formulars berechnet und in sngRange gespeichert).
Damit landet der Datensatzzeiger aber bei größeren Datenmengen nicht zuverlässig auf dem ersten und letzten Datensatz. Dies realisieren wir im Else-Teil der If…Then-Bedingung, die prüft, ob sich der Slider innerhalb des Rechtecks befindet. Eine weitere If…Then-Bedingung ermittelt, ob der Slider links oder rechts herausrutschen würde, und stellt die Eigenschaft AbsolutePosition des Recordset-Objekts entsprechend auf den ersten beziehungsweise letzten Datensatz ein. Da AbsolutePosition für den ersten Datensatz den Index 0 vergibt, verwendet die Prozedur entsprechend die Werte 0 und Me.Recordset.RecordCount -1. Die Ereignisprozedur cmdSlider_MouseMove sieht nun wie in Listing 1 aus.
Listing 1: Diese Prozedur stellt den Datensatzzeiger auf die dem Slider entsprechende Position.
Private Sub cmdSlider_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single) Dim sngNewX As Single If Button = 1 Then sngNewX = Me!cmdSlider.Left + X - sngX If sngNewX >= sngFrameLeft And sngNewX + sngSliderWidth <= sngFrameLeft + sngFrameWidth Then Me!cmdSlider.Left = Me!cmdSlider.Left + X - sngX Me.Recordset.AbsolutePosition = _ Me.Recordset.RecordCount * (Me!cmdSlider.Left - sngFrameLeft) / (sngRange) Else If sngNewX < sngFrameLeft Then Me.Recordset.AbsolutePosition = 0 Else Me.Recordset.AbsolutePosition = Me.Recordset.RecordCount - 1 End If End If End If End Sub