Live-Forum - Die aktuellen Beiträge
Anzeige
Archiv - Navigation
1368to1372
Aktuelles Verzeichnis
Verzeichnis Index
Übersicht Verzeichnisse
Vorheriger Thread
Rückwärts Blättern
Nächster Thread
Vorwärts blättern
Anzeige
HERBERS
Excel-Forum (Archiv)
20+ Jahre Excel-Kompetenz: Von Anwendern, für Anwender
Userform dynamisch anpassen
18.07.2014 14:33:04
Erik
Liebe Gemeinde,
ich beiße mir gerade die Zähne an folgender Herausforderung aus und hoffe, bei euch Trost zu finden:
Ausgangslage
Ich habe ein Userform, in dem ich verschiedene Steuerelemente zur Laufzeit erzeuge. U.a. CommandButtons, deren Click-Ereignis ich über eine Klasse und WithEvents abfange.
Das funktioniert wunderbar.
Das Problem:
Einer dieser Buttons löst ein Sub mit folgendem Code aus:

With MeinUserform      'MeinUserform existiert bereits und enthält die dynamisch erzeugten  _
Steuerelemente
.Height = 400
.Width = 200
.Caption = "Hauptmenü"
.ScrollBars = fmScrollBarsNone
.Controls.Clear
End With

Dieser Code funktioniert wunderbar. Wie schaffe ich es nun, nachdem ich alle Steuerelemente entfernt habe, neue Steuerelemente zur Laufzeit einzufügen?
Folgendes habe ich bisher erfolglos probiert:
Versuch #1

Dim mybutton As MSForms.CommandButton
Dim myForm
Set myForm = ThisWorkbook.VBProject.VBComponents("MeinUserform")
With MeinUserform
.Height = 400
.Width = 200
.Caption = "Hauptmenü"
.ScrollBars = fmScrollBarsNone
.Controls.Clear
End With
Set mybutton = myForm.designer.Controls.Add("Forms.CommandButton.1", "MyButton")
Versuch #2

Dim frmNew
Dim cmdWeiter As MSForms.CommandButton
Set frmNew = ThisWorkbook.VBProject.VBComponents("MeinUserform")
Set cmdWeiter = frmNew.designer.Controls.Add("forms.CommandButton.1")
With cmdWeiter
.Top = 5
.Left = 5
.Width = 150
.Height = 30
.Caption = "Weiter"
.Name = "cmdWeiter"
End With
With frmNew
.Properties("Width") = 200
.Properties("Height") = 200
.Properties("Caption") = "Hauptmenü"
End With

Die Fehlermeldung lautet jeweils: "Laufzeitfehler 91: Objektvariable oder With-Blockvariable nicht festgelegt"
Zum Hintergrund:
Da ich gern alle Steuerelemente auf Basis einer vorliegenden Tabelle dynamisch erzeugen möchte, würde ich gern das vorhandene Userform als Container benutzen und immer wieder anpassen wollen.
Es geht natürlich alles händisch, aber ich will bei der Aufgabe etwas über Klassenprogrammierung, WithEvents und eben dynamisch erzeugte Steuerelemente lernen.
Ich danke jenem welchen, der mir Brotkrumen hinwirft, die mich hoffentlich zum Ziel führen.
Dank und Gruß
Erik

8
Beiträge zum Forumthread
Beiträge zu diesem Forumthread

Betreff
Datum
Anwender
Anzeige
AW: Userform dynamisch anpassen
18.07.2014 17:44:31
Mullit
Hallo,
vergiß den Designer;
Du kannst der Form direkt zur Laufzeit Controls hinzufügen:
Klassenmodul des Userforms:
Option Explicit
Private Sub CommandButton1_Click()
With Controls.Add(bstrProgID:="Forms.CommandButton.1", Name:="cmdWeiter", Visible:=True)
.Top = 5
.Left = 5
.Width = 150
.Height = 30
.Caption = "Weiter"
End With
End Sub

Gruß,

AW: Userform dynamisch anpassen
21.07.2014 08:56:26
Erik
Hallo Mullit,
vielen Dank für deine Antwort. Leider bekomme ich die Fehlermeldung: "Fehler beim Kompilieren: Variable nicht definiert."
Ich weiß nicht, ob ich die Voraussetzungen gut beschrieben habe. Ich mag es nochmal präzisieren.
Ich habe ein Userform erstellt, das standardmäßig leer ist (keine Steuerelemente enthält). Im Quellcode des Userforms habe ich einen Code, der die Steuerelemente erst zur Laufzeit erzeugt.
Mit einer WithEvents-Anweisung in einem Klassenmodul fange ich das Click-Event verschiedener Menübuttons ab.
Mein Ziel ist es, das von mir erstellte Userform als Container zu benutzen, also es immer wieder an verschiedene Szenarien, d.h. in Abhängigkeit von den Steuerelementen anzupassen.
Ich danke dir Mullit, aber es hat leider nocht nicht geholfen.
Ich grübel gerade darüber, mein Vorhaben innerhalb des Userform-Quellcodes umzusetzen.
Für weitere Hinweise bin ich dankbar.
Gruß
Erik

Anzeige
AW: Userform dynamisch anpassen
22.07.2014 16:48:59
Mullit
Hallo,
das war mir schon klar, allerdings kann der Fehler nicht bei meinem Code auftreten, da wird nämlich keine Variable verwendet....!
Du hast entweder bei einem der drei Übergabeparameter den Doppelpunkt vergessen, oder noch etwas zusätzliches in den Code eingefügt ....
Der Code war auch nur ein Ansatz, wie Du Controls zur Laufzeit erstellst.
Den Zugriff über die Klasse hab' ich schon zunächst mal Dir überlassen, aber wenn wir schon dabei sind, hier ein Bsp. für eine CommandButtonKlasse.
Der letzte Button generiert wieder einen neuen Button:
' ********************************************************************** 
' Modul: UserForm1 Typ: Userform 
' ********************************************************************** 

Option Explicit

Private mlngBlockStep As Long
Private mcolCommandButtons As Collection

Private Sub UserForm_Activate()
Const MAX_BUTTON As Long = 9
Dim aobjButton(1 To MAX_BUTTON) As clscmdButton
Dim ialngIndex As Long
prplngBlockStep = 3
Set mcolCommandButtons = New Collection
For ialngIndex = 1 To MAX_BUTTON
     Set aobjButton(ialngIndex) = New clscmdButton
     With aobjButton(ialngIndex)
         Set .prpcmdButton = Controls.Add(bstrProgID:="Forms.CommandButton.1", Visible:=True)
         With .prpcmdButton
             If ialngIndex > 1 Then
               If (ialngIndex - 1) Mod prplngBlockStep = 0 Then
                 .Top = aobjButton(ialngIndex - 1).prpcmdButton.Top + _
                   aobjButton(ialngIndex - 1).prpcmdButton.Height + 20
               Else
                 .Top = aobjButton(ialngIndex - 1).prpcmdButton.Top
               End If
             ElseIf ialngIndex = 1 Then
               .Top = 5
             End If
             If (ialngIndex - 1) Mod prplngBlockStep = 0 Or ialngIndex = 1 Then _
               .Left = 5 _
             Else: .Left = aobjButton(ialngIndex - 1).prpcmdButton.Left + _
               aobjButton(ialngIndex - 1).prpcmdButton.Width + 20
             .Width = 150
             .Height = 30
             .Caption = "Weiter" & ialngIndex
         End With
      End With
      prpcolCommandButtons.Add aobjButton(ialngIndex)
Next
Erase aobjButton
End Sub

Private Sub UserForm_Terminate()
 Set mcolCommandButtons = Nothing
End Sub

Friend Property Get prpcolCommandButtons() As Collection
 Set prpcolCommandButtons = mcolCommandButtons
End Property

Friend Property Get prplngBlockStep() As Long
 prplngBlockStep = mlngBlockStep
End Property

Friend Property Let prplngBlockStep(ByVal pvlngVariable As Long)
 mlngBlockStep = pvlngVariable
End Property

' ********************************************************************** 
' Modul: clscmdButton Typ: Klassenmodul 
' ********************************************************************** 

Option Explicit

Private WithEvents mcmdButton As CommandButton

Private Sub Class_Terminate()
 Set mcmdButton = Nothing
End Sub

Private Sub mcmdButton_Click()
   MsgBox mcmdButton.Name
   If mcmdButton.Name = TypeName(mcmdButton) & UserForm1.prpcolCommandButtons.Count Then _
     Call prcNewButton
End Sub

Friend Property Get prpcmdButton() As CommandButton
 Set prpcmdButton = mcmdButton
End Property

Friend Property Set prpcmdButton(ByVal pvcmdButton As CommandButton)
 Set mcmdButton = pvcmdButton
End Property

' ********************************************************************** 
' Modul:  Typ: Standardmodul 
' ********************************************************************** 

Option Explicit

Public Sub prcNewButton()
  Dim objCmdButton As clscmdButton
  Dim objCommandButton As clscmdButton
  Dim lngIndex As Long
  Set objCommandButton = New clscmdButton
  With objCommandButton
      Set .prpcmdButton = UserForm1.Controls.Add( _
         bstrProgID:="Forms.CommandButton.1", Visible:=True)
      With .prpcmdButton
            Set objCmdButton = _
              UserForm1.prpcolCommandButtons.Item(UserForm1.prpcolCommandButtons.Count)
            If UserForm1.prpcolCommandButtons.Count Mod UserForm1.prplngBlockStep = 0 Then
              .Left = 5
              .Top = objCmdButton.prpcmdButton.Top + _
                 objCmdButton.prpcmdButton.Height + 20
            Else
              .Top = objCmdButton.prpcmdButton.Top
              .Left = objCmdButton.prpcmdButton.Left + _
                 objCmdButton.prpcmdButton.Width + 20
            End If
         .Width = 150
         .Height = 30
         .Caption = "WeiterNeu" & UserForm1.prpcolCommandButtons.Count + 1
      End With
  End With
  UserForm1.prpcolCommandButtons.Add objCommandButton
  Set objCommandButton = Nothing
  Set objCmdButton = Nothing
End Sub



VBA/HTML - CodeConverter für Office-Foren
AddIn für Excel/Word 2000-2010 - komplett in VBA geschrieben von Lukas Mosimann
Projektbetreuung durch mumpel



Code erstellt und getestet in Office 14

Vielleicht kommst Du damit etwas weiter...
Gruß,

Anzeige
AW: Userform dynamisch anpassen
23.07.2014 09:22:52
Erik
Hallo Mullit,
erst einmal: baie baie dankie für dieses Futter! Ich habe es gleich ausprobiert. Wenn ich deinen Code unverändert übernehme, passiert folgendes, wenn ich das Userform öffne:
Ich sehe 9 Buttons in einer Matrix mit 3 mal 3 Zeilen und Spalten. Wenn ich den letzten Button anklicke (Button 9), dann fügt dein Konstrukt dem Userform einen weiteren Button hinzu. Wenn ich den neuen letzten Button (Button 10) drücke, wird wieder ein neuer Button hinzugefügt usw.
Nun bin ich gerade am Verstehen deines Codes und habe zu bestimmten Stellen ein paar Fragen.
---
UserForm1

Option Explicit
Private mlngBlockStep As Long
Private mcolCommandButtons As Collection

Fragerunde 1:
Soweit ich den Teil verstehe, passiert hier folgendes:
- Du legst eine Variable vom Typ Long fest, die später die Anzahl der Spalten auf der Userform trägt.
- Du legst eine Collection fest, in die später sämtliche zur Laufzeit erstellte Buttons abgelegt werden.
Liege ich soweit richtig?

Private Sub UserForm_Activate()
Const MAX_BUTTON As Long = 9
Dim aobjButton(1 To MAX_BUTTON) As clscmdButton
Dim ialngIndex As Long
prplngBlockStep = 3

Fragerunde 2:
- Du legst hier eine Konstante fest, mit der du die Anzahl der zu erstellenden Buttons dimensionierst.
- Du initialisierst eine Variable vom Typ Long, mit der du später in der For-Schleife arbeitest
- Du legst fest, dass es drei Spalten auf dem UserForm gibt.
Habe ich das auch richtig interpretiert?

Set mcolCommandButtons = New Collection
For ialngIndex = 1 To MAX_BUTTON
Set aobjButton(ialngIndex) = New clscmdButton
With aobjButton(ialngIndex)
Set .prpcmdButton = Controls.Add(bstrProgID:="Forms.CommandButton.1", Visible:=True)
With .prpcmdButton
If ialngIndex > 1 Then
If (ialngIndex - 1) Mod prplngBlockStep = 0 Then
.Top = aobjButton(ialngIndex - 1).prpcmdButton.Top + _
aobjButton(ialngIndex - 1).prpcmdButton.Height + 20
Else
.Top = aobjButton(ialngIndex - 1).prpcmdButton.Top
End If
ElseIf ialngIndex = 1 Then
.Top = 5
End If
If (ialngIndex - 1) Mod prplngBlockStep = 0 Or ialngIndex = 1 Then _
.Left = 5 _
Else: .Left = aobjButton(ialngIndex - 1).prpcmdButton.Left + _
aobjButton(ialngIndex - 1).prpcmdButton.Width + 20
.Width = 150
.Height = 30
.Caption = "Weiter" & ialngIndex
End With
End With
prpcolCommandButtons.Add aobjButton(ialngIndex)
Next
Erase aobjButton

Fragerunde 3:
- Das meine ich gut zu verstehen: Du initialisierst eine Collection als Sammelbehälter für alle Buttons.
- Du erzeugst anhand der Klasse clscmdButton neun Buttons, deren Eigenschaften du anhand der vorhergehenden Buttons (.Left/.Top) festlegst.
- Du speicherst jeden Button in der Collection.
- Du löschst anschließend den Inhalt von aobjButton.
Habe ich das richtig wiedergegeben?

End Sub
Private Sub UserForm_Terminate()
Set mcolCommandButtons = Nothing
End Sub

- Du gibst die Collection wieder frei bzw. du zerstörst das Objekt.

Friend Property Get prpcolCommandButtons() As Collection
Set prpcolCommandButtons = mcolCommandButtons
End Property
Friend Property Get prplngBlockStep() As Long
prplngBlockStep = mlngBlockStep
End Property
Friend Property Let prplngBlockStep(ByVal pvlngVariable As Long)
mlngBlockStep = pvlngVariable
End Property

Fragerunde 4:
- Wozu dieser Teil? Ich weiß, dass es sich um Eigenschaften handelt. Sind das Eigenschaften des Userforms? Einmal handelt sich um die Button-Collection und einmal um die Spaltenanzahl.
---
Modul1

Dim objCmdButton As clscmdButton
Dim objCommandButton As clscmdButton
Dim lngIndex As Long
Set objCommandButton = New clscmdButton
With objCommandButton
Set .prpcmdButton = UserForm1.Controls.Add( _
bstrProgID:="Forms.CommandButton.1", Visible:=True)

- Du hast eine neue Instanz der Klasse clscmdButton erstellt.
- Die Klasse hat die Eigenschaft prpcmdButton, die einen Button darstellt.
- Anschließend erstellst du einen Button.
Soweit so gut?

With .prpcmdButton
Set objCmdButton = _
UserForm1.prpcolCommandButtons.Item(UserForm1.prpcolCommandButtons.Count)

Die Eigenschaft prpcolCommandButtons stellt die Buttons-Collection des Userforms dar, oder?
Hier verstehe ich das Set nicht ganz, da doch im weiteren Verlauf die Eigenschaften von prpcmdButton angepasst werden?

If UserForm1.prpcolCommandButtons.Count Mod UserForm1.prplngBlockStep = 0 Then
.Left = 5
.Top = objCmdButton.prpcmdButton.Top + _
objCmdButton.prpcmdButton.Height + 20
Else
.Top = objCmdButton.prpcmdButton.Top
.Left = objCmdButton.prpcmdButton.Left + _
objCmdButton.prpcmdButton.Width + 20
End If
.Width = 150
.Height = 30
.Caption = "WeiterNeu" & UserForm1.prpcolCommandButtons.Count + 1
End With
End With

UserForm1.prpcolCommandButtons.Add objCommandButton

Hier wird der neue Button der Button Collection hinzugefügt?

Set objCommandButton = Nothing
Set objCmdButton = Nothing
End Sub

Hier werden die beiden Objekte zerstört.
---
Klasse clscmdButton

Private WithEvents mcmdButton As CommandButton
Private Sub Class_Terminate()
Set mcmdButton = Nothing
End Sub

Wenn die Instanz zerstört wird, dann soll auch das Objekt zerstört werden.

Private Sub mcmdButton_Click()
MsgBox mcmdButton.Name
If mcmdButton.Name = TypeName(mcmdButton) & UserForm1.prpcolCommandButtons.Count Then _
Call prcNewButton
End Sub

Hieraus lese ich, dass nur der letzte Button einen neuen Button generiert. :)

Friend Property Get prpcmdButton() As CommandButton
Set prpcmdButton = mcmdButton
End Property
Friend Property Set prpcmdButton(ByVal pvcmdButton As CommandButton)
Set mcmdButton = pvcmdButton
End Property

Hier werden Eigenschaften der Klasse bestimmt. Die letzte Eigenschaft verstehe ich nicht. Kannst du mir den Zusammenhang erkären?
Mullit, ich hoffe, ich quäle dich nicht. Ich freue mich, wenn du mir eine Rückmeldung gibst, du kannst aber auch schreiben, dass du keinen Bock hast. :)
Dank im Voraus in jedem Fall!
Gruß
Erik

Anzeige
AW: Userform dynamisch anpassen
23.07.2014 09:24:21
Erik
Hallo Mullit,
erst einmal: baie baie dankie für dieses Futter! Ich habe es gleich ausprobiert. Wenn ich deinen Code unverändert übernehme, passiert folgendes, wenn ich das Userform öffne:
Ich sehe 9 Buttons in einer Matrix mit 3 mal 3 Zeilen und Spalten. Wenn ich den letzten Button anklicke (Button 9), dann fügt dein Konstrukt dem Userform einen weiteren Button hinzu. Wenn ich den neuen letzten Button (Button 10) drücke, wird wieder ein neuer Button hinzugefügt usw.
Nun bin ich gerade am Verstehen deines Codes und habe zu bestimmten Stellen ein paar Fragen.
---
UserForm1

Option Explicit
Private mlngBlockStep As Long
Private mcolCommandButtons As Collection

Fragerunde 1:
Soweit ich den Teil verstehe, passiert hier folgendes:
- Du legst eine Variable vom Typ Long fest, die später die Anzahl der Spalten auf der Userform trägt.
- Du legst eine Collection fest, in die später sämtliche zur Laufzeit erstellte Buttons abgelegt werden.
Liege ich soweit richtig?

Private Sub UserForm_Activate()
Const MAX_BUTTON As Long = 9
Dim aobjButton(1 To MAX_BUTTON) As clscmdButton
Dim ialngIndex As Long
prplngBlockStep = 3

Fragerunde 2:
- Du legst hier eine Konstante fest, mit der du die Anzahl der zu erstellenden Buttons dimensionierst.
- Du initialisierst eine Variable vom Typ Long, mit der du später in der For-Schleife arbeitest
- Du legst fest, dass es drei Spalten auf dem UserForm gibt.
Habe ich das auch richtig interpretiert?

Set mcolCommandButtons = New Collection
For ialngIndex = 1 To MAX_BUTTON
Set aobjButton(ialngIndex) = New clscmdButton
With aobjButton(ialngIndex)
Set .prpcmdButton = Controls.Add(bstrProgID:="Forms.CommandButton.1", Visible:=True)
With .prpcmdButton
If ialngIndex > 1 Then
If (ialngIndex - 1) Mod prplngBlockStep = 0 Then
.Top = aobjButton(ialngIndex - 1).prpcmdButton.Top + _
aobjButton(ialngIndex - 1).prpcmdButton.Height + 20
Else
.Top = aobjButton(ialngIndex - 1).prpcmdButton.Top
End If
ElseIf ialngIndex = 1 Then
.Top = 5
End If
If (ialngIndex - 1) Mod prplngBlockStep = 0 Or ialngIndex = 1 Then _
.Left = 5 _
Else: .Left = aobjButton(ialngIndex - 1).prpcmdButton.Left + _
aobjButton(ialngIndex - 1).prpcmdButton.Width + 20
.Width = 150
.Height = 30
.Caption = "Weiter" & ialngIndex
End With
End With
prpcolCommandButtons.Add aobjButton(ialngIndex)
Next
Erase aobjButton

Fragerunde 3:
- Das meine ich gut zu verstehen: Du initialisierst eine Collection als Sammelbehälter für alle Buttons.
- Du erzeugst anhand der Klasse clscmdButton neun Buttons, deren Eigenschaften du anhand der vorhergehenden Buttons (.Left/.Top) festlegst.
- Du speicherst jeden Button in der Collection.
- Du löschst anschließend den Inhalt von aobjButton.
Habe ich das richtig wiedergegeben?

End Sub
Private Sub UserForm_Terminate()
Set mcolCommandButtons = Nothing
End Sub

- Du gibst die Collection wieder frei bzw. zerstörst du das Objekt.

Friend Property Get prpcolCommandButtons() As Collection
Set prpcolCommandButtons = mcolCommandButtons
End Property
Friend Property Get prplngBlockStep() As Long
prplngBlockStep = mlngBlockStep
End Property
Friend Property Let prplngBlockStep(ByVal pvlngVariable As Long)
mlngBlockStep = pvlngVariable
End Property

Fragerunde 4:
- Wozu dieser Teil? Ich weiß, dass es sich um Eigenschaften handelt. Sind das Eigenschaften des Userforms? Einmal handelt sich um die Button-Collection und einmal um die Spaltenanzahl.
---
Modul1

Dim objCmdButton As clscmdButton
Dim objCommandButton As clscmdButton
Dim lngIndex As Long
Set objCommandButton = New clscmdButton
With objCommandButton
Set .prpcmdButton = UserForm1.Controls.Add( _
bstrProgID:="Forms.CommandButton.1", Visible:=True)

- Du hast eine neue Instanz der Klasse clscmdButton erstellt.
- Die Klasse hat die Eigenschaft prpcmdButton, die einen Button darstellt.
- Anschließend erstellst du einen Button.
Soweit so gut?

With .prpcmdButton
Set objCmdButton = _
UserForm1.prpcolCommandButtons.Item(UserForm1.prpcolCommandButtons.Count)

Die Eigenschaft prpcolCommandButtons stellt die Buttons-Collection des Userforms dar, oder?
Hier verstehe ich das Set nicht ganz, da doch im weiteren Verlauf die Eigenschaften von prpcmdButton angepasst werden?

If UserForm1.prpcolCommandButtons.Count Mod UserForm1.prplngBlockStep = 0 Then
.Left = 5
.Top = objCmdButton.prpcmdButton.Top + _
objCmdButton.prpcmdButton.Height + 20
Else
.Top = objCmdButton.prpcmdButton.Top
.Left = objCmdButton.prpcmdButton.Left + _
objCmdButton.prpcmdButton.Width + 20
End If
.Width = 150
.Height = 30
.Caption = "WeiterNeu" & UserForm1.prpcolCommandButtons.Count + 1
End With
End With

UserForm1.prpcolCommandButtons.Add objCommandButton

Hier wird der neue Button der Button Collection hinzugefügt?

Set objCommandButton = Nothing
Set objCmdButton = Nothing
End Sub

Hier werden die beiden Objekte zerstört.
---
Klasse clscmdButton

Private WithEvents mcmdButton As CommandButton
Private Sub Class_Terminate()
Set mcmdButton = Nothing
End Sub

Wenn die Instanz zerstört wird, dann soll auch das Objekt zerstört werden.

Private Sub mcmdButton_Click()
MsgBox mcmdButton.Name
If mcmdButton.Name = TypeName(mcmdButton) & UserForm1.prpcolCommandButtons.Count Then _
Call prcNewButton
End Sub

Hieraus lese ich, dass nur der letzte Button einen neuen Button generiert. :)

Friend Property Get prpcmdButton() As CommandButton
Set prpcmdButton = mcmdButton
End Property
Friend Property Set prpcmdButton(ByVal pvcmdButton As CommandButton)
Set mcmdButton = pvcmdButton
End Property

Hier werden Eigenschaften der Klasse bestimmt. Die letzte Eigenschaft verstehe ich nicht. Kannst du mir den Zusammenhang erkären?
Mullit, ich hoffe, ich quäle dich nicht. Ich freue mich, wenn du mir eine Rückmeldung gibst, du kannst aber auch schreiben, dass du keinen Bock hast. :)
Dank im Voraus in jedem Fall!
Gruß
Erik

Anzeige
AW: Userform dynamisch anpassen
23.07.2014 22:40:18
Mullit
Hallo,
zu 1)
Im Prinzip richtig; strenggenommen wird in der Collection die Automatisierungsklasse des CommandButtons, also das Objekt aobjButton(ialngIndex) vom Typ clscmdButton abgelegt...
zu 2) + 4)
Die Blockgröße soll auch in prcNewButton ausgelesen werden können, darum habe ich hier eine Eigenschaft mit Lesezugriff erstellt;
der Schreibzugriff ist allerdings überflüssig und könnte auch entfernt werden (s.u.)
zu Modul1:
Hier verstehe ich das Set nicht ganz, da doch im weiteren Verlauf die Eigenschaften
von prpcmdButton angepasst werden?

Das ist richtig, aber die Eigenschaften des neu erstellten Buttons objCommandButton.prpcmdButton werden unter Zuhilfenahme der Eigenschaften des gerade gedrückten Button objCmdButton.prpcmdButton, der sich als letztes Element in der Collection befindet, gesetzt.
Um auf dieses Element zugreifen zu können, wird es einer Objektvariablen vom Typ clscmdButton zugewiesen.
zu Klasse clscmdButton:
Die letzte Eigenschaft verstehe ich nicht. Kannst du mir den Zusammenhang erkären?

Die beiden Eigenschaftsprozeduren sprechen beide dieselbe Eigenschaft an, nämlich prpcmdButton, der sämtliche Eigenschaften und Methoden des neu erstellten Buttons zugewiesen wird:
Property Get ermöglicht den Lesezugriff, Property Set den Schreibzugriff.
Den Code im Activator und prcNewButton könntest Du noch weiter kürzen:
' ********************************************************************** 
' Modul: UserForm1 Typ: Userform 
' ********************************************************************** 

Option Explicit

Private mlngBlockStep As Long
Private mcolCommandButtons As Collection

Private Sub UserForm_Activate()
Const MAX_BUTTON As Long = 9
Dim aobjButton(1 To MAX_BUTTON) As clscmdButton
Dim ialngIndex As Long
mlngBlockStep = 3
Set mcolCommandButtons = New Collection
For ialngIndex = 1 To MAX_BUTTON
     Set aobjButton(ialngIndex) = New clscmdButton
     With aobjButton(ialngIndex)
         Set .prpcmdButton = Controls.Add(bstrProgID:="Forms.CommandButton.1", Visible:=True)
         With .prpcmdButton
             If ialngIndex > 1 Then
               If (ialngIndex - 1) Mod prplngBlockStep = 0 Then
                 .Top = aobjButton(ialngIndex - 1).prpcmdButton.Top + _
                   aobjButton(ialngIndex - 1).prpcmdButton.Height + 20
                 .Left = 5
               Else
                 .Top = aobjButton(ialngIndex - 1).prpcmdButton.Top
                 .Left = aobjButton(ialngIndex - 1).prpcmdButton.Left + _
                    aobjButton(ialngIndex - 1).prpcmdButton.Width + 20
               End If
             Else
               .Top = 5
               .Left = 5
             End If
             .Width = 150
             .Height = 30
             .Caption = "Weiter" & ialngIndex
         End With
      End With
      prpcolCommandButtons.Add aobjButton(ialngIndex)
Next
Erase aobjButton
End Sub

Private Sub UserForm_Terminate()
 Set mcolCommandButtons = Nothing
End Sub

Friend Property Get prpcolCommandButtons() As Collection
 Set prpcolCommandButtons = mcolCommandButtons
End Property

Friend Property Get prplngBlockStep() As Long
 prplngBlockStep = mlngBlockStep
End Property

' ********************************************************************** 
' Modul:  Typ: Standardmodul 
' ********************************************************************** 

Option Explicit

Public Sub prcNewButton()
  Dim objCmdButton As clscmdButton
  Dim objCommandButton As clscmdButton
  Set objCommandButton = New clscmdButton
  With UserForm1.prpcolCommandButtons
       Set objCmdButton = .Item(.Count)
       With objCommandButton
            Set .prpcmdButton = UserForm1.Controls.Add( _
               bstrProgID:="Forms.CommandButton.1", Visible:=True)
            With .prpcmdButton
                  If UserForm1.prpcolCommandButtons.Count Mod UserForm1.prplngBlockStep = 0 Then
                    .Left = 5
                    .Top = objCmdButton.prpcmdButton.Top + _
                       objCmdButton.prpcmdButton.Height + 20
                  Else
                    .Top = objCmdButton.prpcmdButton.Top
                    .Left = objCmdButton.prpcmdButton.Left + _
                       objCmdButton.prpcmdButton.Width + 20
                  End If
               .Width = 150
               .Height = 30
               .Caption = "WeiterNeu" & UserForm1.prpcolCommandButtons.Count + 1
            End With
       End With
       .Add objCommandButton
  End With
  Set objCommandButton = Nothing
  Set objCmdButton = Nothing
End Sub



VBA/HTML - CodeConverter für Office-Foren
AddIn für Excel/Word 2000-2010 - komplett in VBA geschrieben von Lukas Mosimann
Projektbetreuung durch mumpel



Code erstellt und getestet in Office 12

Das ganze diente natürlich nur als Beispiel, an das Du Deine eigenen Voraussetzungen anpassen mußt.
Will man für unterschiedliche Projekte die Controls-Erstellung allgemeingültiger gestalten,
kann man im Activate-Event auch standardisierte Routinen verwenden, denen man Optional die benötigten
Eigenschaften übergibt.
Dazu gibt's hier von Nepumuk ein sehr gutes Beispiel für CommandbarControls, was Du Dir für Userform-Controls umschreiben müsstest...
Gruß,

Anzeige
AW: Userform dynamisch anpassen
24.07.2014 18:11:52
Erik
Hallo Mullit,
wow! Ich danke dir! Ich habe das Prozedere soweit nachvollziehen können, dass ich es testen und ausprobieren mag.
Eine letzte Frage und dann habe ich erstmal genug "Futter" zum Lernen und Tüfteln:
Wenn ich Ereignisse für zur Laufzeit erstellte Steuerelemente erzeugen/abfangen möchte, kann ich ja eine Klasse anlegen, wie du es im Beispiel auch getan hast.
Muss ich für jedes Steuerelement (ComboBox, TextBox, CommandButton) eine eigene Klasse anlegen? Respektive ist das möglich:

Private WithEvents mcmdButton As CommandButton
Private WithEvents mcmdCombo As ComboBox
'etc.
Ich danke dir und freue mich schon, wenn meine neuen Erkenntnisse produktiv umsetzen kann. :)
Gruß
Erik

Anzeige
AW: Userform dynamisch anpassen
25.07.2014 20:09:50
Mullit
Hallo Erik,
prima;
zur Frage:
technisch möglich schon, i.d.R. solltest Du aber für jede Control-Klasse eine eigene Automatisierungsklasse anlegen, da Du die Controls i.d.R. mit unterschiedlicher Anzahl und an verschiedenen Stellen im Code erzeugst; da möchte man nicht für jede Control-Klasse die Automatisierungsschnittstellen der anderen Control-Klassen unnötigerweise miterzeugen.
Wenn Du Dich etwas "warmgelaufen" hast, dann schau Dir mal Teil 5 von Nepumuks Symbolleistentut. an, ein sehr gutes Beispiel, wie man innerhalb von Klassen Klassen erzeugt und auf diese zugreift.
Damit hast Du dann gleich ein voll funktionsfähiges Addon für den VBE-Editor und kannst versuchen, das Prinzip auf Userform-Controls zu übertragen...
Gruß, Mullit
Anzeige

11 Forumthreads zu ähnlichen Themen

Anzeige
Anzeige
Anzeige

Links zu Excel-Dialogen

Beliebteste Forumthreads (12 Monate)

Anzeige

Beliebteste Forumthreads (12 Monate)

Anzeige
Anzeige
Anzeige