Dynamic 动态创建的用户表单、命令按钮和文本框:不注册文本框更改

Dynamic 动态创建的用户表单、命令按钮和文本框:不注册文本框更改,dynamic,excel,user-controls,vba,Dynamic,Excel,User Controls,Vba,注意:第一次发布关于代码的问题-有史以来。我没有接受过VBA方面的正式培训,我所学到的一切都是通过经验或在网上学到的 我正在为雇主做一些工作。我正在创建一个调度系统,我不希望用户在设计模式下访问表单。因此,我通过代码动态创建表单(我希望这是正确的术语)。我通过代码创建一个用户表单,并通过代码添加所有控件。我在命令按钮上有一个单击事件,在该事件上存储用户输入的数据并关闭表单 代码很复杂(对我来说),分为许多表、子例程和类,但下面是一些代码片段,它们以某种方式组合成几个子例程,应该可以解释这种情况。

注意:第一次发布关于代码的问题-有史以来。我没有接受过VBA方面的正式培训,我所学到的一切都是通过经验或在网上学到的

我正在为雇主做一些工作。我正在创建一个调度系统,我不希望用户在设计模式下访问表单。因此,我通过代码动态创建表单(我希望这是正确的术语)。我通过代码创建一个用户表单,并通过代码添加所有控件。我在命令按钮上有一个单击事件,在该事件上存储用户输入的数据并关闭表单

代码很复杂(对我来说),分为许多表、子例程和类,但下面是一些代码片段,它们以某种方式组合成几个子例程,应该可以解释这种情况。在此例程中,在工作表\u选择\u更改事件中显示表单。表单由一个文本框和一个命令按钮组成。单击命令按钮时,会出现一个消息框,显示文本框中的文本

表单显示良好,单击事件“激发”。但是,与文本框中的更改有关的事件似乎不会触发,即,如果文本框中的文本发生更改,则这些更改不会显示在消息框中。如果我在关闭表单之前(单击命令按钮之前)停止该过程,进入新创建的表单的代码并从表单本身运行代码,那么一切都会正常工作

动态编写代码时,是什么阻止了textbox事件的触发?我错过什么了吗?代码如下所示

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    Call Add_Form
End Sub


Private Sub Add_Form()
        Dim VBProj As VBIDE.VBProject
        Dim VBComp As VBIDE.VBComponent

        Set VBProj = ActiveWorkbook.VBProject
        VBProj.VBComponents.Add (vbext_ct_MSForm)

        Dim myForm As Object
        Set myForm = ThisWorkbook.VBProject.VBComponents("UserForm1")

        Call AddControlToForm(ThisWorkbook.VBProject. _
                      VBComponents("UserForm1"), "CommandButton", 60, _
                      20, 135, 90, "btnSave", "Save")
        Call AddControlToForm(ThisWorkbook.VBProject. _
                      VBComponents("UserForm1"), "TextBox", 80, _
                      20, 90, 90, "txtTest")

        Dim Line As Integer
        Line = myForm.CodeModule.CountOfLines

        myForm.CodeModule.InsertLines Line + 1, "Private Sub UserForm_Initialize()"
        myForm.CodeModule.InsertLines Line + 2, "Me.txtTest.SetFocus"
        myForm.CodeModule.InsertLines Line + 3, "Me.txtTest.Text = ""Change Text"""
        myForm.CodeModule.InsertLines Line + 4, "End Sub"


        Dim NewButton As MSForms.CommandButton
        Set NewButton = myForm.Designer.Controls.Item(btnSave)

        myForm.CodeModule.InsertLines Line + 5, "Private Sub btnSave_Click()"
        myForm.CodeModule.InsertLines Line + 6, "  Unload me"
        myForm.CodeModule.InsertLines Line + 7, "End Sub"

        myForm.CodeModule.InsertLines Line + 8, "Private Sub btnSave" & _
                "_Exit(ByVal Cancel As MSForms.ReturnBoolean)"
        myForm.CodeModule.InsertLines Line + 9, "    MsgBox(UserForm1.txtTest.Text)"
        myForm.CodeModule.InsertLines Line + 10, "End Sub"
    Call ShowForm("UserForm1")
    Call RemoveForm("UserForm1")
End Sub

Public Sub AddControlToForm(objForm As Object, strCtlType As String, intWidth As _
                        Integer, intHeight As Integer, intTop As Integer, _
                        intLeft As Integer, strName As String, _
                        Optional strCaption As String = "!%!@")
    Dim objControl As Object
    Set oForm = objForm

    Set objControl = oForm.Designer.Controls.Add("Forms." & strCtlType & ".1")
    With objControl
        .Name = strName
        .Width = intWidth
        .Height = intHeight
        .Top = intTop
        .Left = intLeft
    End With

    If strCaption <> "!%!@" Then
        With objControl
            .Caption = strCaption
        End With
    End If


End Sub

Private Sub ShowForm(strFormName As String)

    Dim objForm As Object

    Set objForm = ThisWorkbook.VBProject.VBComponents(strFormName)

    VBA.UserForms.Add(objForm.Name).Show

End Sub


Private Sub RemoveForm(strFormName As String)
    Dim VBProj As VBIDE.VBProject
    Dim VBComp As VBIDE.VBComponent

    Set VBProj = ActiveWorkbook.VBProject
    Set VBComp = VBProj.VBComponents(strFormName)
    VBProj.VBComponents.Remove VBComp
End Sub
Private子工作表\u selection更改(ByVal目标作为范围)
呼叫添加表单
端接头
专用子添加表格()
将VBProj设置为VBIDE.VBProject
将VBComp作为VBIDE.VBComponent进行调整
设置VBProj=ActiveWorkbook.VBProject
VBProj.VBComponents.Add(vbext\U ct\MSU表单)
将myForm设置为对象
设置myForm=ThisWorkbook.VBProject.VBComponents(“UserForm1”)
调用AddControlToForm(ThisWorkbook.VBProject)_
VBComponents(“UserForm1”),“CommandButton”,60_
20、135、90,“保存”、“保存”)
调用AddControlToForm(ThisWorkbook.VBProject)_
VBComponents(“UserForm1”),“TextBox”,80_
20、90、90,“TXT测试”)
将线变暗为整数
Line=myForm.CodeModule.countofline
myForm.CodeModule.InsertLines行+1,“私有子用户表单_初始化()
myForm.CodeModule.InsertLines行+2,“Me.txtTest.SetFocus”
myForm.CodeModule.InsertLines行+3,“Me.txtest.Text=”“Change Text”“”
myForm.CodeModule.InsertLines行+4,“结束子”
将新按钮设置为MSForms.CommandButton
Set NewButton=myForm.Designer.Controls.Item(btnSave)
myForm.CodeModule.InsertLines行+5,“专用子btnSave_单击()
myForm.CodeModule.InsertLines行+6,“卸载我”
myForm.CodeModule.InsertLines行+7,“结束子”
myForm.CodeModule.InsertLines行+8,“专用子btnSave”和_
“_Exit(ByVal Cancel As MSForms.ReturnBoolean)”
myForm.CodeModule.InsertLines行+9,“MsgBox(UserForm1.txtest.Text)”
myForm.CodeModule.InsertLines行+10,“结束子”
调用ShowForm(“UserForm1”)
调用RemoveForm(“UserForm1”)
端接头
公共子AddControlToForm(对象为objForm,字符串为strCtlType,宽度为intWidth)_
整数,整数为整数,整数为整数_
intLeft为整数,strName为字符串_
可选str选项为String=“!%!@”)
作为对象的Dim OBJ控件
形式集=对象形式
设置objControl=oForm.Designer.Controls.Add(“Forms.”&strctlttype&“.1”)
带对象控制
.Name=strName
.Width=intWidth
.高度=高度
.Top=intTop
.Left=intLeft
以
如果选择“!%!@”,则
带对象控制
.Caption=str选项
以
如果结束
端接头
私有子ShowForm(strFormName作为字符串)
作为对象的Dim objForm
设置objForm=this工作簿.VBProject.VBComponents(strFormName)
VBA.UserForms.Add(objForm.Name).Show
端接头
私有子RemoveForm(strFormName作为字符串)
将VBProj设置为VBIDE.VBProject
将VBComp作为VBIDE.VBComponent进行调整
设置VBProj=ActiveWorkbook.VBProject
设置VBComp=VBProj.VBComponents(strFormName)
VBProj.VBComponents.Remove VBComp
端接头

根据您问题中的信息,您希望在某人退出名为
txtest
的文本框后触发事件。同时,您为
btn\u保存按钮创建了
退出事件的代码。因此,您需要更改此行:

    myForm.CodeModule.InsertLines Line + 8, "Private Sub btnSave" & _
            "_Exit(ByVal Cancel As MSForms.ReturnBoolean)"
myForm.CodeModule.InsertLines Line + 9, "    MsgBox(UserForm1.txtTest.Text)"
为此:

    myForm.CodeModule.InsertLines Line + 8, "Private Sub txtTest" & _
            "_Exit(ByVal Cancel As MSForms.ReturnBoolean)"
编辑在下面的一些评论之后,现在我明白了。所以,改变这一行:

    myForm.CodeModule.InsertLines Line + 8, "Private Sub btnSave" & _
            "_Exit(ByVal Cancel As MSForms.ReturnBoolean)"
myForm.CodeModule.InsertLines Line + 9, "    MsgBox(UserForm1.txtTest.Text)"
在这一点上:

myForm.CodeModule.InsertLines Line + 9, "    MsgBox Me.txtTest.Text"
似乎
UserForm1
可能是一个令人困惑的问题,因此您可以用这种建议的方式设置对userform的引用。这解决了我测试代码中的问题

顺便说一下,你的问题写得很好。如果您在网络的支持下自己编写了此代码,我只能向您表示祝贺。:)继续编程

谢谢你的评论:)虽然这在我的帖子中肯定不清楚,“_Exit”事件与“btnSave”关联,因为我将在几个文本框中使用“parents”。在这种形式下,每个文本框对输出都有贡献,因此我想触发“btnSave_Exit”(或“Click”)事件上的代码。但是,即使将“_Exit”事件切换为“txtest”,并且在运行时在文本框中进行了用户更改,消息框仍会在“_Exit”事件时读取原始(更改前)文本框文本。我需要消息框在文本框中注册更改。思想?