Dynamisch erstellte Textboxen auslesen

.. das wohl mächtigste Werkzeug in Bill Gates' Büro-Sippe. Ob reine Formeln, PowerQuery oder VBA. Hier bleiben kaum Wünsche unerfüllt.
Benutzeravatar
d'r Bastler
Beiträge: 832
Registriert: 29. Aug 2022, 13:20
Hat sich bedankt: 224 Mal
Danksagung erhalten: 118 Mal

Dynamisch erstellte Textboxen auslesen

#1

Beitrag von d'r Bastler »

Moin allerseits,

es ist wohl heute schon mein erster Veggie-Tag im Jahr 2025: zwei ganz dicke Tomaten auf den Augen und ein Blumenkohl als Hirn ...

Sorry, ich finde ums Mäusemelken keine Lösung für mein Thema. Okay - wo geht's los? In einer manuell erstellten USF habe ich zwei CommandButtons (cdmOkay, cmdChange). Der USF füge ich im USF_Activate je nach einem Public definiertem String sCase mehr oder weniger viele Textboxen hinzu, für die neben ihrer Position, verschiedenen Formaten jeweils ein Text definiert werden. Andere TBX gibt es nicht.

Das klappt soweit wunderbar. Je nach sCase erhalte ich die ein oder andere perfekte USF.

Dann passieren in den Textboxen Änderungen, die ich zurück an den Ursprung ihrer Vorgänger ( die .TextFrame.Characters.Text-Eigenschaft verschiedener Shapes) schreiben möchte. Das Adressieren der Shapes funktioniert problemlos, das Schreiben von freiem Text auch.

Nur nicht mit dem Text aus den TBX :?:

Hier der kommentierte Code (in der USF), der bereits die Existenz und Adressierbarkeit der TBX prüft. Die beiden >>>>Fehlerzeilen<<<< sind auskommentiert und markiert.

Code: Alles auswählen

Private Sub cmdOkay_Click()                     'dieser Button ist in den Eigenschaften der USF definiert
Dim i As Integer, c As Integer
Dim ctr As Control
                                                'die TBX werden im USF_Activate dynamisch generiert, positioniert und mit Text gefüllt
    For Each ctr In Me.Controls                 'dieser kleine Test schreibt erfolgreich alle TBX mit korrektem Namen und Text
        If TypeName(ctr) = "TextBox" Then
            Debug.Print ctr.Name & " - " & ctr.Text
        End If                                  'VBA kann also darauf zugreifen
    Next

    If sCase = "row" Then                       'hier haben die Shapes die gleiche Kennziffer wie die tbx
        For i = 1 To 8
            'MC.Shapes("Chr_" & iCallRow + i - 1).TextFrame.Characters.Text = Me.tbx_(i).Text   ''>>>>Fehlermeldung Methode oder Datenobjekt nicht gefunden<<<
        Next i
    End If
    If sCase = "col" Then                       'hier haben die Shapes von den tbx abweichende (aber korrekt berechnete) Kennziffern
        c = 1
        For i = 1 To 9
            'MC.Shapes("Chr_" & iCallCol + i + c - 1).TextFrame.Characters.Text = usf_Input.tbx_(i).Text ''>>>>Fehlermeldung wie oben <<<
            c = c + 8
        Next i
    End If
    
MsgBox sCase                                    'nur zur Kontrolle des Direktfensters, das
Application.Run ("PERSONAL.XLSB!ciw")           'hier per Sub komplett gelöscht wird
    Unload Me                                   'die USF hat ihren Job getan
End Sub
Wo liegt mein Denkfehler? Hat jemand eine Idee? Vorab lieben Dank!

Schöne Grüße
d'r Bastler von den VBAsteleien.de
Win 10 + Office 2019 & Win11 + Office 2021 + Visio 2019 pro & macOS.X15 + Office2019pro & Android12 & XL365
xlKing
Beiträge: 52
Registriert: 30. Mai 2024, 19:42
Hat sich bedankt: 5 Mal
Danksagung erhalten: 52 Mal
Kontaktdaten:

Re: Dynamisch erstellte Textboxen auslesen

#2

Beitrag von xlKing »

Hi Bastler,

ich glaube hier hast du dich vertan: Me.tbx_(i).Text Kann es sein, dass du Me.Controls("tbx_" & i) meinst? Das gleiche dann für die andere Zeile.

Gruß Mr. K.
Benutzeravatar
d'r Bastler
Beiträge: 832
Registriert: 29. Aug 2022, 13:20
Hat sich bedankt: 224 Mal
Danksagung erhalten: 118 Mal

Re: Dynamisch erstellte Textboxen auslesen

#3

Beitrag von d'r Bastler »

Hi MiB,

mit

Code: Alles auswählen

Dim dict As Dictionary: Set dict = New Dictionary

If sCase = "col" Then
    i = 1
        For Each ctr In Me.Controls
            If TypeName(ctr) = "TextBox" Then
                dict.Add i, UCase(ctr.Text)
                i = i + 1
            End If
        Next
        c = 0
        For i = 1 To 9
            MC.Shapes("Chr_" & iCallCol + c).TextFrame.Characters.Text = dict(i)
            c = c + 8
        Next i
    End If
ist mir inzwischen ein "eleganter" :lol: Workaround gelungen.

Aber Dein einfaches Definieren des fehlenden Objekts (und das war der entscheidende Hinweis in der Fehlermeldung) ist natürlich die perfekte Lösung! :v:

Vielen Dank!

und was mache ich jetzt mit Tomaten und Blumenkohl? :(
d'r Bastler von den VBAsteleien.de
Win 10 + Office 2019 & Win11 + Office 2021 + Visio 2019 pro & macOS.X15 + Office2019pro & Android12 & XL365
knobbi38
Beiträge: 25
Registriert: 20. Okt 2024, 14:15
Hat sich bedankt: 2 Mal
Danksagung erhalten: 19 Mal
Kontaktdaten:

Re: Dynamisch erstellte Textboxen auslesen

#4

Beitrag von knobbi38 »

Hallo d'r Bastler,

hier mal eine kleine Anregung, so etwas elegant per OOP zu lösen:

Angenommen, deine Shapes befinden sich im Worksheet "Tabelle1", dann könntest du im Codemodul von Tabelle1 eine Property anlegen:

Code: Alles auswählen

Option Explicit

Public Property Let ShapeText(ByVal Index As Long, ByVal NewValue As Variant)
  Me.Shapes(Index).TextFrame.Characters.Text = NewValue
End Property

Public Property Get ShapeText(ByVal Index As Long) As Variant
  ShapeText = Me.Shapes(Index).TextFrame.Characters.Text
End Property
Dann könntest auf den Text deiner Shapes einfach so zugreifen (Beispiel im Direktfenster):

Code: Alles auswählen

Tabelle1.ShapeText(1) = "Hallo Shape 1"  ' Zuweisung neuer Text
? Tabelle1.ShapeText(1)
So etwas geht natürlich auch analog mit den Textboxen in der Userform. Zum synchronisieren zwischen den Shapes und den Textboxen bräuchte man dann nur eine kleine Schleife, kein Dictionary, keine globale Variablen usw. :)

Ich weiß, du bist kein Freund von OOP, aber ...

Grüße
Knobbi38
Benutzeravatar
d'r Bastler
Beiträge: 832
Registriert: 29. Aug 2022, 13:20
Hat sich bedankt: 224 Mal
Danksagung erhalten: 118 Mal

Re: Dynamisch erstellte Textboxen auslesen

#5

Beitrag von d'r Bastler »

Moin Knobbi,

dass ich OOP nicht mögen würde, ist mir nicht bekannt ;) Allerdinges gebe ich gerne zu, dass ich mich mit Public Properties mangels Bedarf noch nicht so beschäftigt habe.

Meine Frage oben bezog sich auf den Weg Textbox.Text -> Shape.Text. Wenn ich Deinen neuen Code richtig verstanden habe, beschreibst Du die Gegenrichtung Shape.Text -> Textbox.Text. Die löse ich so:

Code: Alles auswählen

.Text = MC.Shapes("Chr_" & iCallRow + i - 1).TextFrame.Characters.Text
Was ist der Vorteil der Public Property?

An andere Stelle habe ich mal den Code-Bandwurm Application.WorkSheetFunction durch einen Zweilzeiler
Public app as Application, wsf as WorkSheetfunction [Sub ...] Set app = Application: Set wsf = Worksheetfunction
auf
app.wsf
reduziert. Wenn eine Property helfen könnte, auch den Bandwurm Shape("xy").Textframe.Characters.Text zu kürzen, wäre das ein interessanter Ansatz.


Vielleicht Sicher kann ich ja was lernen und meinen Bedarf entsprechend erkennen.

Schöne Grüße
d'r Bastler von den VBAsteleien.de
Win 10 + Office 2019 & Win11 + Office 2021 + Visio 2019 pro & macOS.X15 + Office2019pro & Android12 & XL365
knobbi38
Beiträge: 25
Registriert: 20. Okt 2024, 14:15
Hat sich bedankt: 2 Mal
Danksagung erhalten: 19 Mal
Kontaktdaten:

Re: Dynamisch erstellte Textboxen auslesen

#6

Beitrag von knobbi38 »

Hallo,

ich habe durchaus beide Wege beschrieben: den Text eines Shapes zuzuweisen (Property Let) und auszulesen (Property Get).

Der Code

Code: Alles auswählen

.Text = MC.Shapes("Chr_" & iCallRow + i - 1).TextFrame.Characters.Text
würde dann zu

Code: Alles auswählen

.Text = MC.ShapeText(i)
Aber wie du richtig bemerkt hast, habe ich nur den Part für die Shapes beschrieben, den für die Textboxes wollte ich eigentlich dir überlassen, weil ich die Interna deiner UF nicht kenne.

Im Gegensatz zu deiner Adressierungsart über den Namen eines Shapes, wird bei meinem Vorschlag schlichtweg der Index in der Shapes-Auflistung verwendet. Die Zuordnung, welches Shape mit welcher Textbox korrespondiert, erfolgt als nur über diesen Index und nicht über Namen.

Um so etwas auf die UF mit den dynamischen Textboxen zu übertragen, würde ich beim Anlegen der Textboxen, deren Namen, oder noch einfacher, eine Objektreferenz auf die Textbox, in einem Array speichern. So kannst du unmittelbar per Arrayindex die gewünschte Textbox ansprechen, ohne über die Controls-Auflistung gehen zu müssen. Das Array mit den Textbox-Referenzen wird erst wieder im QueryClose oder Terminate Ereignis gelöscht.

Es gibt einen langen Diskurs über Vorteile von Properties vs. Feldern, aber der eigentlich wichtigstes Vorteil m.M.n. dürfte die Datenkapselung sein, d.h., die Implementierung kann geändert werden ohne das der aufrufende Code davon betroffen ist. Außerdem lassen sich damit Zugriffsmöglichkeiten umsetzen, wie z.B. ReadOnly, ReadOnce, WriteOnly oder WriteOnce, was so mit Feldern nicht möglich wäre. Zusätzlich lassen sich so auch Validierungsregeln umsetzen.

Gruß
Knobbi38
Folgende Benutzer bedankten sich beim Autor knobbi38 für den Beitrag:
d'r Bastler
Antworten

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 0 Gäste