spinnifex
Goto Top

VBA Code dynamisch erstellen

Servus allerseits,

nach Stunden der erfolglosen Suche im Netz wende ich mich an Euch mit folgendem Thema:

Voraussetzungen: Excel 2019, ein Workbook mit zwei Tabellen (Werte/Kategorien), in VBA eine dynamisch erstellte Userform, mit einer Reihe von CommandButtons, was soweit auch wunderbar funktioniert. Der usf_initialize-Code als Auszug:
iDist = 30
For i = 1 To iCat
Set ctr = Me.Controls.Add("Forms.CommandButton.1", "CAT_" & i, True)  
sCat = wsK.Cells(i, 2)
sConTip = wsK.Cells(i, 1)
    With ctr
        .Height = 20
        .Top = 15
        .Left = iDist * i
        .Width = 28
        .Caption = sCat
        .ControlTipText = sConTip & " " & ctr.Name  
        .Enabled = True
    End With
Next i

Mein Problem: Ich habe nun iCat (z.B. 10) CommandButtons, für die ich je eine Sub benötige, die OnClick auszuführen ist. Lässt sich dieser Code irgendwie ebenfalls dynamisch erzeugen, oder kann man einfach alle Klicks auf Controlseiner Userform abfangen? (Das habe ich als Vorschlag mithilfe einer Klassegefunden, von deren Programmierung ich leider genau keine Ahnung habe) Der Event Userform_OnClick nimmt nur Klicks außerhalb von Controls entgegen.

Bisher behelfe ich mir mit deaktivierten Grafiken und dem Auslesen der MouseDown-Koordinaten und Select Case True ...

Hat jemand eine schlauere Idee??

Ganz lieben Dank und eine geruhsame Nacht / schöne Woche!

Spinnifex

Content-Key: 6143719898

Url: https://administrator.de/contentid/6143719898

Printed on: April 27, 2024 at 15:04 o'clock

Mitglied: 6017814589
Solution 6017814589 Feb 27, 2023 updated at 08:16:52 (UTC)
Goto Top
Die Klasse ist der richtige und vernünftigste Weg
von deren Programmierung ich leider genau keine Ahnung habe
Das lässt sich einfach ändern
usw.

back-to-topKlasse "clsButton" erstellen
' öffentliche Property für die Zuweisung des Buttons zu dieser Instanz  
Public WithEvents cButton As MSForms.CommandButton

' Click Event das dann jeweils für jeden Button ausgeführt wird  
Private Sub cButton_Click()
    MsgBox "Button '" & cButton.Caption & "' clicked."  
End Sub

screenshot

back-to-topBsp. Code einer Userform mit Nutzung der Klasse für die angelegten Buttons
' Collection für die Button Klasseninstanzen  
Dim btnCollection As New Collection

Private Sub UserForm_Initialize()
    ' Variablen  
    Dim btnCount As Integer, btnClass As clsButton, cmd As MSForms.CommandButton
    ' Anzahl an Buttons  
    btnCount = 4
    ' Collection initialisieren  
    Set btnCollection = New Collection
    ' für Anzahl an Buttons  
    For i = 1 To btnCount
        ' erstelle einen neuen Button  
        Set cmd = Me.Controls.Add("Forms.CommandButton.1", "button" & i)  
        ' platziere den Button  
        cmd.Top = 10
        cmd.Left = 60 * i
        cmd.Width = 50
        cmd.Caption = "Button_" & i  
        ' erstelle eine neue Klasseninstanz  
        Set btnClass = New clsButton
        ' weise der öffentlichen Button-Variable der Instanz den aktuellen Button zu  
        Set btnClass.cButton = cmd
        ' füge die Instanz der Collection hinzu  
        btnCollection.Add btnClass
    Next
End Sub
Und schon nutzt du für jeden Button ein und die selbe Event-Prozedur und kannst bspw. anhand des Namens oder einen anderen Property die du entsprechend setzt die Buttons unterscheiden.

h.
Member: spinnifex
spinnifex Feb 27, 2023 at 13:14:14 (UTC)
Goto Top
Moin Hagelschaden! [lange Pause]
Ich fass' es nicht! [lange Pause]

Es sind inzwischen irgendetwas zwischen fünf und zehn Jahre, die ich mich jetzt als autodidaktischer Amateur mit VBA beschäftige und war entsprechend oft in Tutorials und Foren unterwegs, um nach "Schnürsenkeln für Lauflernschuhe" zu fragen.

Aber nicht ein einziges Mal habe ich eine derart tolle Hilfe erhalten!

Nicht nur, dass Du einen komplett hervorragend kommentierten (und sicherlich funktionierneden) Code einstellst, sondern zudem auch noch Links als Hilfe zur Selbsthilfe lieferst, ist allerbestes Forenvorbild.

Nach diesem ersten Einstieg ins Thema muss ich mich wohl endlich trauen und eigene Erfahrungen mit Klassen sammeln. Also nichts mehr mit basteln auf Grundschulniveau, jetzt muss ich wohl nach Klasse 5 face-wink

"... chon nutzt du für jeden Button ein und die selbe Event-Prozedur und kannst bspw. anhand ..."
Genau so hatte ich mir das vorgestellt, werde, nachdem die Buttons nur nummeriert sind, allerdings aus einer Tabelle gezogene sprechendeTag-Eigenschaften zur Steuerung der Prozeduren nutzen.

Hagelschaden! Ein sehr herzliches Dankeschön für diesen super Beitrag, von dem ich sicher bin, dass er auch vielen anderen hilft.

Spinnifex
Member: spinnifex
spinnifex Feb 27, 2023 at 13:46:35 (UTC)
Goto Top
Nachtrag:

Meine Idee mit der .Tag-Eigenschaft ließ sich leider nicht verwirklichen (falsch! geht natürlich. Hatte einen anderen Fehler übersehen face-sad), so muss jetzt der .Nameher, der aus einem aus der Tabelle gezogenen String aktualisiert wird.

sCat = wsK.Cells(i, 2)
Set cmd = Me.Controls.Add("Forms.CommandButton.1", sCat)  

Der Code lief auf Anhieb (fast, es fehlte die Deklaration von i, das hat man nun von Option Explicit face-wink) reibungslos durch und ließ sich in nur wenigen Minuten in den meinen integrieren.

Hagelschaden! Superklasse! Nochmals vielen Dank!
Member: spinnifex
spinnifex Feb 27, 2023 at 16:59:26 (UTC)
Goto Top
Moin nochmal,

auch wenn Hagelschlag schon eine prima Lösung geliefert hat, habe ich das Thema noch einmal auf ungelöst gesetzt, weil ich jetzt im zweiten Teil nicht weiterkomme, vermutlich einer Kleinigkeit wegen. Die cButtons funktionieren perfekt, ich habe auch meinen Code in der Klasse so minimiert, dass ich die tatsächlichen Prozeduren in einem allgemeinen Modul in einer Sub Categorie (sCat as String), also mit Parameter ausführen kann.
Option Explicit 'clsButton  
Public WithEvents cButton As MSForms.CommandButton
Private Sub cButton_Click()
    Application.Run "Categorie", cButton.Caption  
End Sub

Nach dem selben Muster habe ich nun auch das Rudel Textboxen, das ich in der Userform benötige in einer neuen Klasse clsTextboxen / cTextbox umsetzen und mit dem Change-Event zu einer korrekten Antwort verleiten können:
Option Explicit 'clsTextbox  
Public WithEvents cTextbox As MSForms.TextBox
Private Sub cTextbox_Change()
    MsgBox "cTextbox", , cTextbox.Name  
End Sub

Jetzt versuche ich diese Textboxen über ihren Namen aus einem allgemeinen Modul zu füllen, formatieren, de/enablen, usw. Die UserForm1 erklärt mir bei diesen Versuchen:
For i = 1 To Len(sWord)
       UserForm1.tbx_(i).Text = Mid(sWord, i, 1)
Next i
"Methode oder Datenobjekt nicht gefunden" und markiert UserForm1.tbx_(i).Text.

Was muss ich tun, dass die Textboxen, nachweislich mit den korrekten Namen vorhanden und im der laufenden USF ansprechbar, von meinem Makro gefunden werden?

Lieben Dank vorab!
Spinnifex
Mitglied: 6017814589
Solution 6017814589 Feb 27, 2023, updated at Feb 28, 2023 at 06:42:03 (UTC)
Goto Top
Userform1.Controls("Blablub").Text = "XYZ"  
habe ich das Thema noch einmal auf ungelöst gesetzt, weil ich jetzt im zweiten Teil nicht weiterkomme
Kann man nur hoffen das das nicht wieder zu einer never ending story mit einem Mischmasch aus x Threadfremdem Fragen mutiert ...
Member: spinnifex
spinnifex Feb 28, 2023 at 17:39:07 (UTC)
Goto Top
Moin Hagelschaden! Ich denke, es ist für Dich besser zu hoffen, dass wir uns nicht IRL begegnen!! ;.) Denn dann könnte es passieren, dass ich Dich für Deine zielführende Hilfe egal wo, wie und möglichst feucht öffentlich knutsche ...face-wink Keine Sorge ... war der Versuch eines dankbaren Scherzes.

Ganz herzlichen Dank! Durch den Hinweis auf die Controls (inklusive der Syntax mit Klammer und Anführung) werde ich wohl auch Versuche mit anderen USF-Klassen erfolgreich realisieren können.

Nochmal lieben Dank und keine Sorge: Ich bin nicht Michael Ende mit einer "Un... [Punkt]

Spinnifex
Member: spinnifex
spinnifex Feb 28, 2023 at 21:17:13 (UTC)
Goto Top
Nachtrag: So siehts dann am lebenden Objekt aus:
For i = 1 To Len(sWord)
    sCtr = "tbx_" & i  
        usfMain.Controls(sCtr).Text = Mid(sWord, i, 1)
Next i
Hier wird ein Wort Buchstabe für Buchstabe auf die Textboxen gesplittet.

Grüße
Spinnifex