【问题标题】:Loop to extract value from checkbox循环从复选框中提取值
【发布时间】:2019-05-28 22:56:00
【问题描述】:

我正在使用的表单有 10 个复选框,值从 1 到 10,用于回答多项选择题。

多个值在技术上是可行的(单击多个框),但不允许使用(在填充时,只能给出一个值)。我无法修改此表单,因此我必须使用此设置。

我需要提取给定的选项并将其粘贴到不同的工作表中。 使用this question,我可以提取每个复选框的值并开发一个 IF 循环。

If ExtractionSheet.Shapes("Check Box 1").OLEFormat.Object.Value = 1 Then

Database.Cells(5, 9).Value = 1

ElseIf ExtractionSheet.Shapes("Check Box 2").OLEFormat.Object.Value = 1 Then

Database.Cells(5, 9).Value = 2

ElseIf ExtractionSheet.Shapes("Check Box 3").OLEFormat.Object.Value = 1 Then

Database.Cells(5, 9).Value = 3

...

但是,这看起来效率不高(我有 3 组,每个表单有 1-10 个复选框和 100 多个表单)。鉴于设置,我无法找到更好的方法。

如何在不使用 IF 循环的情况下改进提取?

EDIT 对表单的更好描述,在 cmets 之后

这是一个简单的 Excel 工作表,其中粘贴了 3 组,每组 10 个复选框元素。

每个表单/工作表都与单个项目相关。在评估期间,对于每个项目,我们将为属性 1(前 10 个复选框)分配一个介于 1 和 10 之间的值,为属性 2(后 10 个复选框)分配一个介于 1 和 10 之间的值,并为属性分配一个介于 1 和 10 之间的值3(第三个 10 个复选框)。

我将在给我数据以填充它的客户面前进行填充(物理单击框)。点击多个框的可能性自然存在;我认为这并不重要,因为我这样做时很多人会看着屏幕,但我可以稍后再添加一个检查。

【问题讨论】:

  • If 不是循环 - 它是一个语句。 ForDo 用于循环
  • 这些在用户表单上吗?
  • 您能否在表单上添加一个事件,以便在选择另一个事件时自动取消选择前一个事件?
  • @Tom 否。但我可以在提取过程中检查是否选择了两个或多个变量并发出警告。
  • @SJR 是的,他们在我的客户提供的 Excel 用户表单上,我会填写。我实际上会做填充(点击框等)

标签: excel vba checkbox


【解决方案1】:

在cmets之后更新:

我对@9​​87654329@ 使用了以下命名约定(仅使用例如 A1 是单元格引用,可能会导致问题)

ChkBox_A1

第一部分表示它是checkbox (ChkBox),第二部分表示A,第三部分表示位置1。使用此命名约定以及当前代码的编写方式,您最多可以拥有 26 个组(即,每个字母对应一个)

我使用即时窗口查看可以在 VBA 编辑器中访问的结果,方法是转到 View->Immediate WindowCtrl+G

此代码将处理每个组的单选。即如果在组中选中了一个复选框,它将取消选择所有其他复选框

对于工作表

此代码位于工作表对象中

替换所有点击语句(例如 ChkBox_A1_Click() 参考您自己的。这可以通过调用 GenerateChkBoxClickStmt 子并将即时窗口中的输出复制并粘贴到您的代码中轻松完成(替换我的)

Option Explicit
Dim ChkBoxChange As Boolean
Private Sub ChkBox_A1_Click()
    If ChkBoxChange = False Then UnselectPreviousChkBox Me.ChkBox_A1
End Sub
Private Sub ChkBox_A2_Click()
    If ChkBoxChange = False Then UnselectPreviousChkBox Me.ChkBox_A2
End Sub
Private Sub ChkBox_B1_Click()
    If ChkBoxChange = False Then UnselectPreviousChkBox Me.ChkBox_B1
End Sub
Private Sub UnselectPreviousChkBox(selected As Object)
    Dim ChkBox As OLEObject

    ChkBoxChange = True

    For Each ChkBox In Me.OLEObjects
        If ChkBox.progID = "Forms.CheckBox.1" Then
            If ChkBox.Name <> selected.Name And Mid(ChkBox.Name, 8, 1) = Mid(selected.Name, 8, 1) Then
                ChkBox.Object.Value = False
            End If
        End If
    Next ChkBox

    ChkBoxChange = False
End Sub
Private Sub GenerateChkBoxClickStmt()
    Dim ChkBox As OLEObject
    ' Copy and paste output to immediate window into here

    For Each ChkBox In Me.OLEObjects
        If ChkBox.progID = "Forms.CheckBox.1" Then
            Debug.Print "Private Sub " & ChkBox.Name & "_Click()"
            Debug.Print vbTab & "If ChkBoxChange = False Then UnselectPreviousChkBox Me." & ChkBox.Name
            Debug.Print "End Sub"
        End If
    Next ChkBox
End Sub

产生以下内容:

这段代码进入一个模块

Option Explicit
Private Function GetChkBoxValues(ChkBoxGroup As Variant) As Long
    Dim ChkBox As OLEObject

    ' Update with your sheet reference
    For Each ChkBox In ActiveSheet.OLEObjects
        If ChkBox.progID = "Forms.CheckBox.1" Then
            If ChkBox.Object.Value = True And Mid(ChkBox.Name, 8, 1) = ChkBoxGroup Then
                GetChkBoxValues = Right(ChkBox.Name, Len(ChkBox.Name) - (Len("ChkBox_") + 1))
                Exit For
            End If
        End If
    Next ChkBox
End Function
Public Sub GetSelectedChkBoxes()
    Dim ChkBoxGroups() As Variant
    Dim Grp As Variant

    ChkBoxGroups = Array("A", "B", "C")

    For Each Grp In ChkBoxGroups
        Debug.Print "Group " & Grp, GetChkBoxValues(Grp)
    Next Grp
End Sub

通过运行GetSelectedChkBoxes,代码将输出到即时窗口:

对于用户表单

类似地,点击事件的语句可以通过取消注释Userform_Initalize sub 中的行来生成

Option Explicit
Dim ChkBoxChange As Boolean
Private Function GetChkBoxValues(Group As Variant) As Long
    Dim ChkBox As Control

    For Each ChkBox In Me.Controls
        If TypeName(ChkBox) = "CheckBox" Then
            If ChkBox.Object.Value = True And Mid(ChkBox.Name, 8, 1) = Group Then
                GetChkBoxValues = Right(ChkBox.Name, Len(ChkBox.Name) - (Len("ChkBox_") + 1))
                Exit For
            End If
        End If
    Next ChkBox
End Function
Private Sub UnselectPreviousChkBox(selected As Control)
    Dim ChkBox As Control
    ChkBoxChange = True
    For Each ChkBox In Me.Controls
        If TypeName(ChkBox) = "CheckBox" Then
            If ChkBox.Name <> selected.Name And Mid(ChkBox.Name, 8, 1) = Mid(selected.Name, 8, 1) Then
                ChkBox.Value = False
            End If
        End If
    Next ChkBox
    ChkBoxChange = False
End Sub
Private Sub ChkBox_A1_Click()
    If ChkBoxChange = False Then UnselectPreviousChkBox Me.ChkBox_A1
End Sub
Private Sub ChkBox_A2_Click()
    If ChkBoxChange = False Then UnselectPreviousChkBox Me.ChkBox_A2
End Sub
Private Sub ChkBox_B1_Click()
    If ChkBoxChange = False Then UnselectPreviousChkBox Me.ChkBox_B1
End Sub
Private Sub userform_initialize()
    ' Comment out once written
    ' GenerateChkBoxClickStmt
End Sub
Private Sub UserForm_Terminate()
    Dim ChkBoxGroups() As Variant
    Dim Grp As Variant

    ChkBoxGroups = Array("A", "B", "C")

    For Each Grp In ChkBoxGroups
        Debug.Print "Group " & Grp, GetChkBoxValues(Grp)
    Next Grp
End Sub
Private Sub GenerateChkBoxClickStmt()
    Dim ChkBox As Control
    ' Copy and paste output to immediate window into here
    For Each ChkBox In Me.Controls
        If TypeName(ChkBox) = "CheckBox" Then
            Debug.Print "Private Sub " & ChkBox.Name & "_Click()"
            Debug.Print vbTab & "If ChkBoxChange = False Then UnselectPreviousChkBox Me." & ChkBox.Name
            Debug.Print "End Sub"
        End If
    Next ChkBox
End Sub

制作:

并在退出时输出以下内容:

【讨论】:

  • 那么这两者之间有什么逻辑吗?
  • 一点也不。我可以将它们重命名为渐进式数字,然后应用您的解决方案。我将如何处理每个表单有 3 组 10 个复选框的事实?
  • 你如何将它们组合在一起?我建议用某种逻辑命名它们。如果没有将它们分组,您还可以应用命名约定来描述复选框与哪个组相关。例如“A组复选框1”等
  • 我可以将我的复选框重命名为 A1、A2...A10、B1、B2...B10 等等。如何编辑您的代码以仅对一组运行?
  • @laureapresa 请看看我的更新。我产生了一个更复杂的答案,它将处理每个组的单个选择,并以WorkSheet 方法或UserForm 说明所有组。如果您有任何问题随时问。请注意GenerateChkBoxClickStmt,因为这些子程序将为您生成所有Click 语句,而不必编写它们(它们基于CheckBox 名称,因此需要正确构造才能工作。我也为您推荐了一种命名模式
猜你喜欢
  • 2021-07-26
  • 1970-01-01
  • 1970-01-01
  • 2014-08-06
  • 1970-01-01
  • 1970-01-01
  • 2020-11-22
  • 2013-06-23
  • 1970-01-01
相关资源
最近更新 更多