Datensatz-Slider

Lies diesen Artikel und viele weitere mit einem kostenlosen, einwöchigen Testzugang.

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.

pic001.png

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

Der Slider kann, wenn Sie diesen zu schnell verschieben, hängen bleiben.

Slider bei manuellem Datensatzwechsel verschieben

Wenn der Benutzer den Datensatz über die Navigationsschaltflächen verschiebt, soll die Position des Sliders entsprechend angepasst werden. Der Wechsel des Datensatzes löst immer das Ereignis Beim Anzeigen des Formulars aus. Dafür legen Sie die Ereignisprozedur aus Listing 2 an. Diese addiert zum linken Rand des Rahmens den der aktuellen Position entsprechenden prozentualen Anteil des vom Slider befahrbaren Bereichs und weist diesen Wert der Eigenschaft Left des Slider-Steuerelements zu.

Listing 2: Einstellen der Slider-Position anhand der Position des Datensatzzeigers

Private Sub Form_Current()
    Me!cmdSlider.Left = sngFrameLeft + Me.Recordset.AbsolutePosition / Me.Recordset.RecordCount * (sngRange)
End Sub

Hinzufügen neuer Datensätze

Die Technik funktioniert leider noch nicht, wenn der Benutzer einen neuen Datensatz zum Formular hinzufügt. Das liegt daran, dass sich der Wert der Eigenschaft AbsolutePosition beim Springen zu einem neuen, leeren Datensatz nicht ändert. Wenn das Formular also 100 Datensätze anzeigt, der Datensatzzeiger auf dem letzten Datensatz steht und Sie zehn weitere Datensätze hinzufügen, ohne auf einen der bestehenden Datensätze zu wechseln, bleibt der Datensatzzeiger bei 100 stehen. Bei großen Datenmengen fällt dies nicht auf und die Gelegenheiten, bei denen man manuell eine relevante Menge Datensätze hinzufügt, sollten überschaubar sein.

Bei kleinen Datenmengen fällt dies jedoch gleich auf, weil sich der Slider immer weiter nach links bewegt, obwohl der Datensatzzeiger doch auf dem jeweils letzten Datensatz stehen sollte. Dies ist jedoch kein Problem: Wir wissen, dass der neue Datensatz erstmal der letzte ist, also können wir den Slider in diesem Fall einfach ganz nach rechts schieben. Dies ermöglichen eine Prüfung der Eigenschaft NewRecord und die entsprechende Reaktion wie in Listing 3.

Listing 3: Positionseinstellung, nun auch für neue Datensätze

Private Sub Form_Current()
    If Not Me.NewRecord Then
        Me!cmdSlider.Left = sngFrameLeft + Me.Recordset.AbsolutePosition / Me.Recordset.RecordCount * (sngRange)
    Else
        Me!cmdSlider.Left = sngFrameLeft + sngRange
    End If
End Sub

Löschen von Datensätzen

Wie wirkt sich das Löschen von Datensätzen auf die Position aus Der Versuch liefert gleich Fehler 3167, Datensatz ist gelöscht. Dieser tritt in der Ereignisprozedur Form_Current beim Versuch auf, nach dem Löschen des Datensatzes auf die Eigenschaft AbsolutePosition zuzugreifen.

Dies birgt ein kleines Dilemma: Wenn die Prozedur nicht auf den Wert von AbsolutePosition zugreifen kann, erschwert dies die Einstellung der Slider-Position. Allerdings ist das auch nicht so schlimm: Die Slider-Position ist sicher nicht kriegsentscheidend, wenn der Benutzer gerade den gewünschten Datensatz vor sich hat, und falls nicht, wird der Slider ja ohnehin gleich wieder vom Benutzer verschoben oder durch eine manuelle änderung der AbsolutePosition richtig positioniert.

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

Testzugang

eine Woche kostenlosen Zugriff auf diesen und mehr als 1.000 weitere Artikel

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar