VBA动态生成用户窗体,将事件绑定到按钮

问题描述 投票:0回答:1

我正在尝试动态创建一个用户窗体并为其分配一个具有行为的按钮,用户窗体和按钮的生成有效,但单击按钮时的操作不起作用...... 这是我的代码(请注意,这是我第一次使用类模块,而且我对事件不熟悉):

名为 ConfPalletsLoader 的模块:

Sub CPL()
Dim fso As New FileSystemObject
Dim ConfigFile As Object
Dim ConfigLines As New Collection
Dim line As String
Dim key As String
Dim value As String

' Open the configuration file
Set ConfigFile = fso.OpenTextFile("C:\TDUFO\pallets.ini", 1)

Do Until ConfigFile.AtEndOfStream
    ConfigLines.Add ConfigFile.ReadLine
Loop
ConfigFile.Close

Dim configDict As Object
Dim inFormSection As Boolean
Dim currentForm As String
Dim i As Long
Dim formInstances As Collection
Set formInstances = New Collection ' To store instances of clsDynamicForm
Dim formInstance As clsDynamicForm

' Iterate over configuration lines
For i = 1 To ConfigLines.Count
    line = Trim(ConfigLines(i))
    
    ' Skip empty lines
    If line = "" Then GoTo ContinueLoop

    ' Detect start of a new form section
    If Left(line, 1) = "[" And Right(line, 1) = "]" Then
        ' If we're already processing a form, display it
        If Not configDict Is Nothing Then
            Set formInstance = New clsDynamicForm
            formInstance.CreateForm configDict
            formInstances.Add formInstance ' Store the instance
            formInstance.ShowForm
        End If
        
        ' Start a new form section
        Set configDict = CreateObject("Scripting.Dictionary")
        currentForm = Mid(line, 2, Len(line) - 2) ' Extract the form name
        inFormSection = True
    ElseIf inFormSection And InStr(line, "=") > 0 Then
        key = Trim(Split(line, "=")(0))
        value = Trim(Split(line, "=")(1))
        configDict.Add key, value
    End If
ContinueLoop:
Next i
' Ensure the last form is created after the loop ends
If Not configDict Is Nothing Then
    Set formInstance = New clsDynamicForm
    formInstance.CreateForm configDict
    formInstances.Add formInstance ' Store the instance
    formInstance.ShowForm
End If
End Sub

名为 clsDynamicForm 的 ClassModule :

Option Explicit
Private buttonHandlers As Collection ' This should persist for the lifetime of the form
Private DynamicForm As Object ' Store the dynamically created form here

Public Sub CreateForm(configDict As Object)
    ' Load the template UserForm and store it in the DynamicForm variable
    Set DynamicForm = LoadFormInstance("TemplateUserForm")
    
    ' Initialize the button handler collection to keep handlers alive
    Set buttonHandlers = New Collection
    
    ' Set the UserForm properties using Object type
    With DynamicForm
        .Width = CLng(configDict("FormWidth"))
        .Height = CLng(configDict("FormHeight"))
        .Top = CLng(configDict("FormTop"))
        .Left = CLng(configDict("FormLeft"))

        ' Add buttons dynamically
        Dim buttonIndex As Long
        buttonIndex = 1
        
        Do While configDict.Exists("Button" & buttonIndex & "Caption")
            Dim btn As MSForms.CommandButton ' Ensure this is MSForms.CommandButton
            Set btn = .Controls.Add("Forms.CommandButton.1")
            
            ' Set button properties
            btn.Caption = configDict("Button" & buttonIndex & "Caption")
            btn.Top = CLng(configDict("Button" & buttonIndex & "Top"))
            btn.Left = CLng(configDict("Button" & buttonIndex & "Left"))
            btn.Width = CLng(configDict("Button" & buttonIndex & "Width"))
            btn.Height = CLng(configDict("Button" & buttonIndex & "Height"))
                
            ' Debugging: Check that the button is created
            Debug.Print "Button created: " & btn.Caption
            
            ' Create a new button handler for each button
            Dim btnHandler As clsButtonHandler
            Set btnHandler = New clsButtonHandler
            btnHandler.AssignButton btn
            
            ' Store the button handler in the collection to keep it in memory
            buttonHandlers.Add btnHandler
            
            ' Increment the button index to create the next button
            buttonIndex = buttonIndex + 1
        Loop
    End With
End Sub


' Show the form modelessly
Public Sub ShowForm()
    DynamicForm.Show vbModeless
End Sub


' Helper function to load a new instance of a UserForm by name
Private Function LoadFormInstance(formName As String) As Object
    Dim frm As Object
    Set frm = VBA.UserForms.Add(formName) ' Load a new instance of the template UserForm
    Set LoadFormInstance = frm ' Return the loaded UserForm instance
End Function

名为 clsButtonHandler 的 ClassModule :

Option Explicit

' This class will handle the button click events
Private WithEvents Button As MSForms.CommandButton ' Ensure this is CommandButton

' Assign the button to the class
Public Sub AssignButton(ByVal btn As MSForms.CommandButton)
    Set Button = btn
    Debug.Print "Button assigned: " & btn.Caption ' Ensure the button is assigned
End Sub

' Handle the click event of the button
Private Sub Button_Click()
    MsgBox "Button clicked: " & Button.Caption, vbInformation
    Debug.Print "Button clicked: " & Button.Caption
    Call ButtonClickedSub
End Sub

名为 TemplateUserForm 的 UserForm,为空。

如果您需要运行我的代码,这是pallets.ini 包含的内容(C:\TDUFO\pallets.ini):

[Form1]
FormWidth = 300
FormHeight = 200
FormTop = 100
FormLeft = 100
Button1Caption = "Button 1"
Button1Top = 30
Button1Left = 50
Button1Width = 80
Button1Height = 30

项目的活跃参考:

Listing

您知道为什么不调用“按钮单击”例程吗?

excel vba
1个回答
0
投票

问题在于

formInstance
的范围为
CPL()
。 当
CPL()
完成时,参考就被破坏了。

Dim formInstance As clsDynamicForm

使

formInstance
变量
Static
将使变量引用保持活动状态,但最好将其设为模块级变量。

Static formInstance As clsDynamicForm
© www.soinside.com 2019 - 2024. All rights reserved.