【问题标题】:Trying to add Textboxes to a userform dynamically?试图动态地将文本框添加到用户窗体?
【发布时间】:2019-12-04 14:45:25
【问题描述】:

我在 Excel 工作簿中有代码,可以帮助我创建大量电子邮件以发送给各种程序的用户。我有一个弹出的用户表单,用户填充了所有需要的信息。但这一次只计算一个应用程序。有人可以与我分享代码,根据选中的复选框动态地将文本框添加到用户窗体吗?

在第一帧中,我有指示哪些应用程序受到影响的复选框,第二帧我有选项按钮来描述什么类型的事件,然后我希望文本框根据勾选的内容显示。

非常感谢任何指导,因为我认为目前这对我来说太深了

我已经对这段代码进行了逆向工程,它添加了我想要的框,但我需要能够用单元格数据填充它们,然后在电子邮件中使用它:

Option Explicit

Dim SpnColct As Collection

Private Sub CommandButton2_Click()

    Dim cSpnEvnt As cControlEvent
    Dim ctlSB As Control
    Dim ctlTXT As Control
    Dim lngCounter As Long

    For lngCounter = 1 To 7
        Set ctlTXT = Me.Frame7.Controls.Add("Forms.TextBox.1", "Text" & lngCounter)
        ctlTXT.Name = "Text" & lngCounter
        ctlTXT.Left = 5
        ctlTXT.Height = 125: ctlTXT.Width = 280
        ctlTXT.Top = (lngCounter - 1) * 125 + 2

        Set cSpnEvnt = New cControlEvent
        Set cSpnEvnt.SP = ctlSB
        Set cSpnEvnt.TXT = ctlTXT
        SpnColct.Add cSpnEvnt

    Next lngCounter

    Me.Frame1.ScrollHeight = (lngCounter - 1) * 17 + 2

End Sub

这添加到一个类模块中:

Option Explicit

Public WithEvents SP As MSForms.SpinButton
Public WithEvents TXT As MSForms.TextBox

Private Sub SP_SpinDown()
    SP.Value = SP.Value - 1
    MsgBox "Spin Down to " & SP.Value
End Sub

Private Sub SP_SpinUp()
    SP.Value = SP.Value + 1
    MsgBox "Spin Up to " & SP.Value
End Sub

Private Sub TXT_Change()
    MsgBox "You changed the value."
End Sub

【问题讨论】:

  • 您不想让所有文本框都存在但禁用/启用哪个复选框被选中?如果你觉得你在这种方式上太深了,不要让自己难过:)
  • 目前有 7 个应用程序,列表可能会变得更大,我目前确实有 7 个文本框,但由于代码太乱,我不想考虑如何添加另一个文本框
  • 如果代码如此混乱,我建议在添加任何其他代码/机制之前先解决这个问题。一段时间后回到凌乱的代码是一场噩梦。
  • 删除它重新开始,不会让它打败我。找到了一些我可以调整以动态添加文本框的代码。现在只需要弄清楚如何从框中读取文本

标签: excel vba textbox userform


【解决方案1】:

更新 这将是一个有点长的一步 - 一步一步看你是否理解它。已将其更改为在 CheckBox_Click 事件上创建文本框,但如果您愿意,可以更改为命令按钮。再这样下去,我认为您需要提出一个新问题。

我最近一直在做类似的事情,发现您遇到问题的原因是由于加载对象的顺序。不幸的是,我目前找不到解释它的链接(如果可以的话会更新),但为了能够实现这一点,你需要一个额外的 Class 来加载对象,否则 Userform 可以'见不到他们。这是我想出的解决方案(使用您的示例)

用户表单:

Option Explicit
Private WithEvents cControls As EventController

Private Sub cControls_Click(ctrl As CheckBoxControl)
    Dim tBox As TextBoxControl
    Dim i As Long
    Dim NextTop As Long, FrameHeight As Long

    For i = 1 To cControls.GetControls.Count
        Debug.Print TypeName(cControls.GetControl(i))
        If TypeName(cControls.GetControl(i)) = "TextBoxControl" Then
            Set tBox = cControls.GetControl(i)
            If tBox.TXT.Parent Is Me.Frame7 Then
                NextTop = tBox.Top + tBox.Height
            End If
        End If
    Next i

    Set tBox = cControls.AddTextBox
    With tBox
        .Height = 125
        .Width = 280
        .Left = 5
        .Top = NextTop
        .TXT.Text = ctrl.cBox.Caption
        FrameHeight = NextTop + .Height
    End With
    If FrameHeight > Me.Frame7.InsideHeight Then
        With Me.Frame7
            .ScrollBars = fmScrollBarsVertical
            .ScrollHeight = FrameHeight
            .Scroll yAction:=6
        End With
    End If

End Sub

Private Sub UserForm_Initialize()
    Dim i As Long
    Dim cBox As CheckBoxControl
    Set cControls = New EventController
    ' This can be set to a userform or a frame
    Set cControls.UserForm = Me
    For i = 1 To 8
        Set cBox = cControls.AddCheckBox
        cBox.cBox.Left = 5
        With cBox.cBox
            .Top = 5 + (i - 1) * .Height
            .Caption = IIf(i = 8, "App Unknown", "App " & i)
        End With
    Next i

End Sub

Private Sub cControls_Change(ctrl As TextBoxControl)
    ' This can be handled in the class instead as you were - just doing it in the userform to show the exposing of the event
    MsgBox ctrl.TXT.Name & " Change"
End Sub

Private Sub cControls_SpinDown(ctrl As TextBoxControl)
    ' This can be handled in the class instead as you were - just doing it in the userform to show the exposing of the event
    With ctrl.SP
        If .Value >0 Then
            .Value = .Value - 1
        End If
    End With
    MsgBox ctrl.SP.Name & " Spin Down"
End Sub

Private Sub cControls_SpinUp(ctrl As TextBoxControl)
' This can be handled in the class instead as you were - just doing it in the userform to show the exposing of the event
    With ctrl.SP
        .Value = .Value + 1
    End With
    MsgBox ctrl.SP.Name & " Spin Up"

End Sub

- 这些需要以粗体命名

事件控制

Option Explicit

Private CtrlCollection As Collection
Private cUserForm As UserForm1

Public Event SpinDown(ctrl As TextBoxControl)
Public Event SpinUp(ctrl As TextBoxControl)
Public Event Change(ctrl As TextBoxControl)
Public Event Click(ctrl As CheckBoxControl)
Public Property Set UserForm(v As UserForm1)
    Set cUserForm = v
End Property
Public Property Get UserForm() As UserForm1
    Set UserForm = cUserForm
End Property
Public Function AddTextBox() As TextBoxControl
    Dim tBox As TextBoxControl
    Set tBox = New TextBoxControl

    tBox.Initialize Me

    CtrlCollection.Add tBox

    Set AddTextBox = tBox

End Function
Public Function AddCheckBox() As CheckBoxControl
    Dim cBox As New CheckBoxControl
    cBox.Initalize Me
    CtrlCollection.Add cBox

    Set AddCheckBox = cBox
End Function
Public Function GetControl(Index As Long)
    Set GetControl = CtrlCollection(Index)
End Function
Public Function GetControls() As Collection
    Set GetControls = CtrlCollection
End Function
Private Sub Class_Initialize()
    Set CtrlCollection = New Collection
End Sub
Public Sub SpinDown(ctrl As TextBoxControl)
    RaiseEvent SpinDown(ctrl)
End Sub
Public Sub SpinUp(ctrl As TextBoxControl)
    RaiseEvent SpinUp(ctrl)
End Sub
Public Sub Change(ctrl As TextBoxControl)
    RaiseEvent Change(ctrl)
End Sub
Public Sub Click(ctrl As CheckBoxControl)
    RaiseEvent Click(ctrl)
End Sub

CheckBoxControl

Option Explicit

Public WithEvents cBox As MSForms.CheckBox
Private cParent As EventController
Public Property Set Parent(v As EventController)
    Set cParent = v
End Property
Public Property Get Parent() As EventController
    Set Parent = cParent
End Property
Public Sub Initalize(Parent As EventController)
    Set Me.Parent = Parent
    Set cBox = Parent.UserForm.Frame1.Controls.Add("Forms.CheckBox.1")
End Sub

Private Sub cBox_Click()
    Parent.Click Me
End Sub

TextBoxControl

Option Explicit

Public WithEvents SP As MSForms.SpinButton
Public WithEvents TXT As MSForms.TextBox
Private cParent As EventController
Public Sub Initialize(Parent As EventController)
    Set Me.Parent = Parent
    With Parent.UserForm.Frame7.Controls
        Set SP = .Add("Forms.SpinButton.1")
        Set TXT = .Add("Forms.TextBox.1")
    End With
End Sub
Public Property Set Parent(v As EventController)
    Set cParent = v
End Property
Public Property Get Parent() As EventController
    Set Parent = cParent
End Property
Public Property Let Left(v As Single)
    TXT.Left = v
    SP.Left = TXT.Left + TXT.Width
End Property
Public Property Get Left() As Single
    Left = TXT.Left
End Property
Public Property Let Top(v As Single)
    TXT.Top = v
    SP.Top = v
End Property
Public Property Get Top() As Single
    Top = TXT.Top
End Property
Public Property Let Height(v As Single)
    TXT.Height = v
    SP.Height = v
End Property
Public Property Get Height() As Single
    Height = TXT.Height
End Property
Public Property Let Width(v As Single)
    TXT.Width = v - SP.Width
    SP.Left = TXT.Left + TXT.Width
End Property
Public Property Get Width() As Single
    Width = TXT.Width + SP.Width
End Property

Public Sub SP_SpinDown()
    Parent.SpinDown Me
'    SP.Value = SP.Value - 1
'    MsgBox "Spin Down to " & SP.Value
End Sub
' The commented out lines below you can either leave in here, or handle in the Userform
Public Sub SP_SpinUp()
    Parent.SpinUp Me
'    SP.Value = SP.Value + 1
'    MsgBox "Spin Up to " & SP.Value
End Sub

Public Sub TXT_Change()
    Parent.Change Me
'    MsgBox "You changed the value."
End Sub

问题源于加载Userform 时未加载控件,因此Userform 尚未注册它们是具有Event 的东西。通过使用中间类,Userform 识别出该类有一个Event,我们在初始化Userform 时静态加载它。然后我们可以在这个Class 中添加我们想要的任何ControlsUserform 将处理它们。

演示:

【讨论】:

  • 这部分代码太棒了。感谢您的帮助。这是更大目标的一部分。我希望能够在第一帧中勾选 1 个或多个,然后勾选下很多选项按钮,然后我希望它可以创建文本框并根据选择的内容填充它们。希望我说得通
  • 我还添加了一张图片来帮助解释我想要实现的目标
  • 干杯 @tom 这几乎是我想要得到它的地方。我目前正在度假,所以想为你的努力喝彩。我现在需要调整您的代码,以便它根据电子邮件类型上勾选的内容填写文本。但在我寻求进一步帮助之前,我会先尝试一下。
  • 现在从假期回来,我决心现在完成这个。我已经多次运行代码以尝试了解正在发生的事情。我在代码中看到在选择任何选项按钮之前填充了文本框。我是否需要扩展代码以准备 5 种可能的电子邮件结果?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多