Home > Artikel > Ausgabe 7/2016 > Flying Controls

Flying Controls

Achtung: Sie sind nicht angemeldet. Wenn Sie Abonnent sind und sich anmelden, lesen Sie den kompletten Artikel, laden das PDF herunter oder probieren die Beispieldatenbank aus (sofern vorhanden).

Fliegende Steuerelemente? Üblicherweise positionieren Sie Textboxen, Labels und Kombinationsfelder fest im Entwurf eines Formulars und ändern an der ergonomischen Gestalt zur Laufzeit nichts mehr. Doch manchmal gibt es gute Gründe für ein dynamisches Layout, bei dem Steuerelemente ihren angestammten Platz verlassen. Einige Anregungen dazu liefert dieser Beitrag.

Beispieldatenbank

Die Beispiele dieses Artikels finden Sie in der Datenbank 1607_FlyingCtls.accdb.

Steuerelemente verschieben

Für die Position jedes Steuerelements sind dessen Eigenschaften Links und Oben im Formular- oder Berichtsentwurf verantwortlich, die Sie entweder durch Ziehen der Elemente mit der Maus ändern, oder durch einen direkten Eintrag im Eigenschaftenblatt. Gleiches gilt für die Breite und Höhe eines Controls.

Unter VBA greifen Sie auf diese Eigenschaften über die Properties Left und Top zu, sowie über Width und Height. Diese Methoden sind nicht schreibgeschützt, so dass Sie über entsprechende Wertzuweisungen die Positionen zur Laufzeit ändern können. Ein Textfeld txtName bringen Sie etwa so in eine andere Position und auf neue Abmessungen:

txtName.Left = 300

txtName.Top = 120

txtName.Width = 2100

txtName.Height = 270

Das Ganze können Sie auch über einen With-Block auf das Control umsetzen und setzen besser noch den Container Me des Steuerelements voran:

With Me!txtName

   .Left = 300

   .Top = 120

   .Width = 2100

   .Height = 270

End With

Die Einheit dieser Werte ist unter Access immer Twips. 15 Twips entsprechen in der Regel 15 Pixeln und ein Zentimeter entspricht etwa 567 Twips. Die Positionsangaben beziehen sich grundsätzlich auf die linke obere Ecke des Steuerelements als seinen Ursprung und sind, entgegen der Aussage in der Access-Hilfe, relativ zum jeweiligen Container. Das kann der Detailbereich sein, aber auch der Kopf- oder Fußbereich. Bei Berichten kommen noch weitere Containerflächen hinzu.

Eine Alternative zum direkten Zuweisen der Werte an Left und Top stellt die Move-Methode dar, die allen Steuerelementen zueigen ist. Mit ihr können Sie die vier Eigenschaften auf einen Schlag einstellen:

Me!txtName.Move 300, 120, 2100, 270

Alle vier Angaben sind optional. Sie können also mit dieser Methode etwa nur Position oder nur die Abmessungen ändern, indem Sie die anderen Parameter weglassen:

Me!txtName.Move 300,120

Me!txtName.Move , , 2100, 270

Schließlich gibt es mit der DoCmd-Anweisung MoveSize noch eine weitere Methode, die in ihren Parametern der Move-Methode der Controls entspricht. Sie wirkt allerdings nicht nur auf Steuerelemente, sondern genauso auf Formularfenster. Das macht zur Bedingung, dass das zu positionierende Element zum Zeitpunkt ihres Aufrufs den Fokus besitzt:

Me!txtName.SetFocus

DoCmd.MoveSize 300, 120, 2100, 270

Auch hier sind alle Parameter optional. Die Methode entkoppelt die Anweisung vom Steuerelement und eignet sich daher nur für Fälle, in denen das Control-Objekt ungewiss ist.

Fliegende Steuerelemente

Das weitgehend sinnfreie Formular frmFlying der Beispieldatenbank demonstriert die Verschiebeeffekte zur Laufzeit (Bild 1). In einer VBA-Schleife werden über den Timer des auf Adressdatensätzen basierenden Formulars sämtliche Steuerelemente fortlaufend verschoben. Damit sie nicht über den Rand hinaus geraten, was Access ohnehin mit einer Fehlermeldung quittieren würde, reflektieren sie quasi billardmäßig von den Seiten. Den Code, der beim Starten des Formulars zunächst ausgeführt wird, finden Sie in Listing 1. Er ist auf den ersten Blick nicht selbsterklärend.

Das Formular frmFlying zeigt in der Gegend herumfliegende Steuerelemente

Bild 1: Das Formular frmFlying zeigt in der Gegend herumfliegende Steuerelemente

Modulweit gelten die Variablen colCtl (Collection-Objekt) und das Array arrXY. Die Collection versammelt indiziert die Namen aller Controls des Formulars, arrXY ist zweidimensional und speichert deren Positionen. Die For-Each-Schleife durchläuft alle Steuerelemente über die Iteratorvariable ctl. Das können Textboxen, Comboboxen oder Labels sein. In colCtl werden per Add-Methode die Indizes (i) der Controls aufgenommen, wobei als Schlüssel jeweils der Steuerelementname herhält. Das Array arrXY wird über ReDim in der zweiten Dimension auf die Zahl der Steuerelemente dimensioniert (Controls.Count) und andererseits auf 1 in der ersten Dimension, was bedeutet, dass zu jedem Array-Element zwei Werte abgespeichert werden können: ein X- und ein Y-Wert für die Positionsverschiebungen. Die Collection dient dazu, um später aus einem Steuerelementnamen seinen Index für arrXY bestimmen zu können. Außerdem wird das Array mit X- und Y-Verschiebefaktoren vorgefüllt, die sich aus Zufallszahlen (Rnd) ergeben. Der Ausdruck

1 + 5 * (Rnd - 0.5)

bewirkt, dass die Klammer positiv oder negativ wird, wenn Rnd größer oder kleiner ist, als 0.5. Der Bereich des Klammerausdrucks beträgt damit -2.5 bis +2.5.

Abschließend wird der Timer des Formulars aktiviert und auf 20 Millisekunden eingestellt, was zu 50 Wiederholungen pro Sekunde führen sollte. Die Prozedur des Timer-Events in Listing 2 nimmt nun die eigentlichen Steuerelementverschiebungen vor und wertet aus, ob sie am Rand des Formulars reflektiert werden sollen.

Private Sub Form_Timer()

     Dim ctl As Access.Control

     Dim i As Long

     

     For Each ctl In Me.Controls

         i = colCtl(ctl.Name)

         ctl.Left = ctl.Left + 30 * arrXY(0, i)

         ctl.Top = ctl.Top + 30 * arrXY(1, i)

         

         If (ctl.Left < 91) Then

             arrXY(0, i) = -arrXY(0, i)

             ctl.Left = 90

         End If

         If ((ctl.Left - 91) > (Me.InsideWidth - ctl.Width)) Then

             arrXY(0, i) = -arrXY(0, i)

             ctl.Left = Me.InsideWidth - ctl.Width - 90

         End If

         If (ctl.Top < 91) Then

             arrXY(1, i) = -arrXY(1, i)

             ctl.Top = 90

         End If

         If ((ctl.Top + 91) > (Me.InsideHeight - ctl.Height)) Then

             arrXY(1, i) = -arrXY(1, i)

             ctl.Top = Me.InsideHeight - ctl.Height - 90

         End If

     Next ctl

     DoEvents

End Sub

Listing 2: Timer-Prozedur des Formulars zum Bewegen der Steuerelemente

Auch hier wird eine Schleife auf alle Controls des Formulars gesetzt. Aus colCtl wird jeweils erst über den Namen der Control-Variable ctl dessen Index für das Array arrXY errechnet und in der Variablen i abgespeichert. Dann wird zu Left und Top des Controls der mit 30 multiplizierte Verschiebewert aus dem Array hinzuaddiert. Je höher dieser Multiplikator, desto schneller bewegt sich das Steuerelement zur Laufzeit über das Formular.

Die anschließenden vier If-Bedingungen überprüfen jeweils mit Kleiner oder Größer als, ob das Control den Formularrand erreicht hat, wobei ein Offset von 90 Twips (= 6 Pixel) mit einbezogen wird. Für den rechten oder unteren Rand ist das etwas komplizierter. Hier muss immer erst von den für die Formularabmessungen verantwortlichen Eigenschaften InsideWidth und InsideHeight die Breite (ctl.Width) oder Höhe (ctl.Height) des Steuerelements abgezogen werden. Trifft die Randbedingung zu, so wird der Verschiebewert im Array negiert, also jeweils X- oder Y-Richtung umgekehrt. Außerdem bekommt das Steuerelement dann eine neue Startposition zugewiesen, damit die Reflektion an einem klaren Raster ausgerichtet erscheint.

Das abschließende DoEvents stellt sicher, dass die Verschiebeoperationen sich visuell auch tatsächlich auswirken und das Formular neu gezeichnet wird. Ohne diese Anweisung käme es zu Rucklern.

Diese eher der Sparte Game-Programmierung zuzuordnende Anwendung soll lediglich andeuten, welche Rechen- und Kodierungsvorgänge beim Verschieben von Steuerelementen anfallen können. Doch es gibt auch nützlichere Verwendungszwecke...

Akkordeon

Nein, nicht um die visuelle Nachbildung des Musikinstruments geht es hier! Sollten Sie mit Webprogrammierung vertraut sein, so kennen Sie möglicherweise aus AJAX-Frameworks das Accordion. Hierbei handelt es sich um Seitenbereiche, die sich dynamisch durch Hoch- und Herunterschieben ein- und ausblenden. Verwendet werden kann dies etwa für Navigationselemente. Das Formular frmAccordion der Beispieldatenbank realisiert so etwas für Kundendatensätze (siehe Bild 2).

Die Akkordion-Navigation links im Formular erlaubt das Filtern der Daten

Bild 2: Die Akkordion-Navigation links im Formular erlaubt das Filtern der Daten

Auf der linken Seite finden Sie alphabetisierte Buttons, die zur Filterung der Datensätze dienen. Ein Klick auf D etwa zeigt im Formular nur noch jene Datensätze an, die mit einem D im Nachnamen beginnen.

Beim Start des Formulars ist das Akkordeon zunächst deaktiviert. Die Buttons links haben dann eine statische Position. Aktivieren Sie jedoch die Checkbox Accordion, so ändert sich die Gestalt etwa, wie in Bild 3. Hier ist bereits das Label-Steuerelement D-F angeklickt worden, was die entsprechenden Buttons zutage fördert. Ein Klick auf Label A-C würde diese wieder ausblenden und stattdessen die Buttons A, B und einblenden. Analog sieht die Sache beim Klick auf G-K aus.

Im Akkordion aktivierte Button-Gruppe nach Klick auf Label D-F

Bild 3: Im Akkordion aktivierte Button-Gruppe nach Klick auf Label D-F

Diese Akkordeon-Navigation spart also Platz im Formular ein, ohne die Funktionalität zu beschränken. Die Version der Beispieldatenbank ist übrigens nicht für produktive Zwecke geeignet, weil die Buttons ab K fehlen. Rüsten Sie diese gegebenenfalls nach. Im Entwurf des Formulars (Bild 4) wären dann links weitere Labels und Schaltflächen unterzubringen. Wie wir noch sehen werden, spielt deren genaue Position im Entwurf keine Rolle.

Entwurfsansicht von frmAccordion mit den Navigations-Buttons links

Bild 4: Entwurfsansicht von frmAccordion mit den Navigations-Buttons links

Für die Realisierung des Akkordeons kommen zwei dynamische Eigenschaften der Buttons und Labels zum Tragen: Einmal die Top-Eigenschaft, und dann die Visible-Eigenschaft. Denn außer dem Verschieben der Steuerelemente muss auch deren Sichtbarkeit gesteuert werden.

Alle zum Akkordeon gehörenden Steuerelemente sind im Entwurf, egal, ob Label oder Schaltfläche, vertikal von oben nach unten mit N plus einem Index benannt. Das Label A-C nennt sich damit N1. Der Button A ist N2. Das Label D-F nennt sich N5. Und so fort. Das macht es einfacher möglich, anhand des vertikalen Index auf ein Steuerelement zuzugreifen und es zu positionieren. Listing 3 zeigt mit der Prozedur ResetAccordion, wie die Steuerelemente in Abhängigkeit des Zustands der Checkbox chkAccordion, deren Wert in der Boolean-Variablen bAccordion abgelegt wird, zur Laufzeit verschoben werden.

Private bAccordion As Boolean

Private Sub chkAccordion_AfterUpdate()

     bAccordion = chkAccordion.Value

     ResetAccordion

End Sub

Private Sub ResetAccordion()

     Dim n As Long

     If bAccordion Then

        Me!N1.Top = 660

Sie haben das Ende des frei verfügbaren Teil dieses Artikels erreicht!

Wenn Sie mehr lesen und auf viele weitere Artikel zugreifen möchten, melden Sie sich als Abonnent unter Login an. Falls nicht, bestellen Sie doch einfach ein Jahresabonnement!