Create a Series of dynamically created button by clicking each of them in Excel VBA

后端 未结 2 1154
北荒
北荒 2021-01-16 11:50

Please don\'t consider this question as a repeated question! This question is clearly different from earlier similar-looking queries.

相关标签:
2条回答
  • 2021-01-16 12:23

    Can you try this. A bit rushed, so wouldn't be surprised if something goes wrong, but will come back tomorrow if so.

    Behind the form

    Private col As Collection
    
    Private Sub UserForm_AddControl(ByVal Control As MSForms.Control)
    
    Dim cl As Class2
    Dim ctl As MSForms.CommandButton
    
    Set col = New Collection
    
    For Each ctl In Me.Controls
        Set cl = New Class2
        Set cl.btEvents = ctl
        col.Add cl
    Next ctl
    
    End Sub
    
    Private Sub UserForm_Initialize()
    
    Dim btEx As MSForms.CommandButton
    Set btEx = UserForm1.Controls.Add("Forms.CommandButton.1")
    
    With btEx
        .Top = 12
        .Left = 12
        .Width = 72
        .Height = 36
        .Caption = "Click Me"
    End With
    
    End Sub
    

    Class module The only change here is to add some spacing so the buttons don't appear on top of each other.

    Public WithEvents btEvents As MSForms.CommandButton
    
    Private Sub btEvents_click()
    
    Dim btEx As MSForms.CommandButton
    Set btEx = UserForm1.Controls.Add("Forms.CommandButton.1")
    
    With btEx
        .Top = 30 * UserForm1.Controls.Count
        .Left = 30
        .Width = 72
        .Height = 36
        .Caption = "Click Me"
    End With
    
    End Sub
    

    0 讨论(0)
  • 2021-01-16 12:38

    Implementing a collection of classes, where each class contains a button, is the key to making this work. Drawbacks to the common approach are that the class holds a reference to the UserForm, and the events are handled in the class itself. Ideally, we would like to get all the button code back into the UserForm including the handling of events.

    How can this be done since Collections cannot be declared WithEvents? This can be accomplished by a global notification mechanism:

    UserForm

    Option Explicit
    
    Private WithEvents MyNotifier As Notifier
    Private MyControls As Collection
    
    Private Sub UserForm_Initialize()
       Set MyNotifier = GetNotifier()
       Set MyControls = New Collection
       AddButton
    End Sub
    
    Private Sub MyNotifier_Click()
       AddButton
    End Sub
    
    Private Sub AddButton()
       Dim c As MSForms.CommandButton
       Set c = UserForm1.Controls.Add("Forms.CommandButton.1")
       c.Width = 72
       c.Height = 36
       c.Top = UserForm1.Controls.Count * c.Height
       c.Left = 12
       c.Caption = "Click Me"
    
       Dim mc As MyControl
       Set mc = New MyControl
       mc.Add c
       MyControls.Add mc
    End Sub
    

    There are 3 support modules with this architecture. The first is a module that holds a global notifier. We create and access this notifier through the GetNotifier method. This method guarantees there is one and only one instance.

    Module

    Option Explicit
    
    Private m_Notifier As Notifier
    
    Public Function GetNotifier() As Notifier
       If m_Notifier Is Nothing Then Set m_Notifier = New Notifier
    
       Set GetNotifier = m_Notifier
    End Function
    

    The second is a class that defines the notifier. This singleton class is an event coordinator. It allows redirection of events, in this case from the MyControl class back to the UserControl.

    Notifier Class

    Option Explicit
    
    Public Event Click()
    
    Public Function Click()
       RaiseEvent Click
    End Function
    

    The third is a class that holds the button. The response to the button click event is to call a method of our Notifier which in turn raises an event back to the UserControl:

    MyControl Class

    Option Explicit
    
    Private MyNotifier As Notifier
    Private WithEvents btEx As MSForms.CommandButton
    
    Public Sub Add(ByVal c As MSForms.CommandButton)
       Set MyNotifier = GetNotifier()
       Set btEx = c
    End Sub
    
    Private Sub btEx_Click()
       MyNotifier.Click
    End Sub
    
    0 讨论(0)
提交回复
热议问题