【问题标题】:Remove Dynamically Added Controls from Userform从用户窗体中删除动态添加的控件
【发布时间】:2015-03-03 15:04:00
【问题描述】:

我有一个带有动态添加复选框的 Excel 用户表单。

我使用如下代码添加复选框:

Set chkBox = Me.Controls.Add("Forms.Checkbox.1", "Checkbox" & i)

我想删除所有这些复选框。

Dim j As Integer
'Remove all dynamically updated checkboxes
For Each cont In Me.Controls
    For j = 1 To NumControls
        If cont.Name = "Checkbox" & j Then
            Me.Controls.Remove ("Checkbox" & j)
        End If
    Next j
Next cont

我收到以下错误消息:

【问题讨论】:

  • 这里的问题之一可能是 " ("Checkbox" & j)" 中的括号
  • 检查它是否失败并验证这是否是在运行时添加的复选框,而不是在设计模式下
  • 回想起来,可能修复我的代码的不是检查,而是一旦找到正确的退出。 @PatrickLepelletier 可能是对的,这可能是检查了错误的复选框。话虽如此,Chris 下面的代码应该可以解决这个问题。
  • 我回到这篇文章,只是想知道为什么我没有看到它:我用 On error resume next 做这些事情

标签: excel vba userform


【解决方案1】:

更好的方法可能是跟踪您创建的控件(例如在集合中),并使用它来删除它们。

这样您的代码就不受名称格式的约束,也可以应用于其他控件类型。

Private cbxs As Collection

Private Sub UserForm_Initialize()
    Set cbxs = New Collection
End Sub

' Remove all dynamicly added Controls
Private Sub btnRemove_Click()
    Dim i As Long
    Do While cbxs.Count > 0
        Me.Controls.Remove cbxs.Item(1).Name
        cbxs.Remove 1
    Loop
End Sub


' Add some Controls, example for testing purposes
Private Sub btnAdd_Click()
    Dim i As Long
    Dim chkBox As Control
    For i = 1 To 10
        Set chkBox = Me.Controls.Add("Forms.CheckBox.1", "SomeRandomName" & i)
        chkBox.Top = 40 + i * 20
        chkBox.Left = 20
        cbxs.Add chkBox, chkBox.Name  '- populate tracking collection
    Next

    ' Demo that it works for other control types
    For i = 1 To 10
        Set chkBox = Me.Controls.Add("Forms.ListBox.1", "SomeOtherRandomName" & i)
        chkBox.Top = 40 + i * 20
        chkBox.Left = 60
        cbxs.Add chkBox, chkBox.Name
    Next

End Sub

【讨论】:

  • 不妨更改变量 chkbox 名称。 +1 用于酷炫的收藏。
  • 谢谢@L42。是的,我会使用通用名称。只是保留它以使 OP 更清楚这与他的原始代码有何关系
  • 感谢您的建议!在这个特定的应用程序中,我想删除在运行时创建的复选框(因此具有特定的命名方案),同时保留所有其他控件。但你是对的,这是更简洁、更通用的代码。 +1
  • @PatrickLepelletier 实际上不,集合项目从 1 开始。(另一方面,字典从 0 开始)。 VBA 可能与起始索引完全不一致
  • 友情提示:假设在第二个循环中对集合的分配应编码为cbxs.Add chkBox, chkBox.Name(而不是chkBox.Add ...,否则会导致运行时错误438 对象不支持此属性或方法 :-) @chrisneilsen `
【解决方案2】:

假设没有其他以“复选框”开头的控件名称,

For Each cont In Me.Controls
    If InStr(cont.Name, "Checkbox") = 1 Then
        Me.Controls.Remove cont.Name
    End If
Next cont

【讨论】:

  • 不错的方法,非常简单但有效。
【解决方案3】:

如果您已经知道控件的名称、类型和数量,为什么要双循环?

请注意,只有在运行时创建的控件才能被删除。

'the following removes all controls created at runtime
Dim i As Long
On Error Resume Next
With Me.Controls
    For i = .Count - 1 to 0 step -1
        .Remove i
    Next i
End With
Err.Clear: On Error GoTo 0

对于你的情况:'如果所有命名都是正确的

Dim j&
For j = 1 To NumControls
    Me.Controls.Remove "Checkbox" & j
Next j

【讨论】:

    【解决方案4】:

    添加对控件的检查似乎可以解决此问题。不完全确定原因,但它确实有效。

       Dim j As Integer
    'Remove all dynamically updated checkboxes
    For Each cont In Me.Controls
        If TypeName(cont) = "CheckBox" Then
            For j = 1 To NumControls
                If cont.Name = "Checkbox" & j Then
                    Me.Controls.Remove cont.Name
                    Exit For
                End If
            Next j
        End If
    Next cont
    

    【讨论】:

    • 循环里面的这个循环在那里做什么?
    • 内部循环正在检查每个控件的数量。在外循环中,我必须控制 A,但我不能完全确定它是控制 1。所以我检查每个数字,直到找到正确的数字。
    • 解决这个问题的不是检查控制,而是退出——当我找到我要找的东西时,我停止寻找。碰巧我的复选框在其他任何事情之前都被选中了。接受的答案更稳定;它不依赖运气:)
    【解决方案5】:

    我使用命令按钮重写了原始代码,只是添加了“Me.Controls.Count”而不是“NumControls”并将“Cont”定义为控件。它似乎对我有用。请让我知道这是否适合您:

    -->

    On Error Resume Next
    Dim Cont As Control
    Dim C As Integer
    'Remove all dynamically updated checkboxes
    For Each Cont In Me.Controls
        For C = 1 To Me.Controls.Count
        If Cont.Name = "CommandButton" & C Then
            Me.Controls.Remove ("CommandButton" & C)
        End If
        Next C
    Next Cont
    

    【讨论】:

      【解决方案6】:

      另一种选择保留哪些控件以及删除哪些控件的方法是使用 .Tag 属性。 这允许在添加控件时对其进行一些精细控制,例如使用 .Tag 作为位域。

      在创建时:

      With Me.Controls.add("Forms.Label.1", Visible:=True)
      {code}
          .Tag = 1
      {more code}
      

      那么到了收拾的时候:

      For Each C In Me.Controls
          If C.Tag = 1 Then Me.Controls.Remove C.Name
      Next
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-26
        • 2016-03-19
        • 1970-01-01
        • 2013-01-16
        相关资源
        最近更新 更多