【问题标题】:VBA Looping through checkboxes and getting its name from excel tableVBA遍历复选框并从excel表中获取其名称
【发布时间】:2021-04-10 07:06:51
【问题描述】:

正如您在上面看到的,我在 Excel 工作表中有一个表格,其中指示 A 可以包含产品 1、产品 2 等等(产品名称因指示而异,这只是为了简单起见!)。

在我的用户表单中显示了类似的格式。我想基本上将我的 excel 表上的指示名称与我的用户表单中的指示名称相匹配。如果它们匹配,则产品 11 获得 A 的产品 1 名称,产品 12 获得 A 的产品 2 名称,依此类推。

我尝试了以下方法,但我才刚刚开始使用 VBA,所以我确信它甚至可能没有意义。


Dim code_ind As String
Dim sel_ind As String
Dim chkbx As Control
Dim labx As Control
Dim i As Integer
Dim col_value As Integer
Dim row_value As Integer

For i = 1 To 8
For j = 1 To 4
For row_value = 4 To 11
col_value = 0

Set chkbx = Me.Controls("seg_l_selInd_" & i)
Set labx = Me.Controls("seg_cb_selInd_" & i & j)

sel_ind = tWb.Worksheets("LALALA").Columns(2).Find(what:=chkbx)

If code_ind = sel_ind Then
    labx.Name = tWb.Worksheets("LALALA").Cells(row_value, 3 + col_value)
    col_value = col_value + 1
End If
Next row_value
Next j
Next i

有什么办法可以做到吗?我知道我可以手动编写名称,但我需要我的工具尽可能灵活。理想情况下,如果将更多信息添加到 excel 表中,用户表单将自动更新。

【问题讨论】:

  • 您的代码不完整。 tWbcode_indchkbx等的值是多少?
  • 不确定我是否理解您想要完成的任务...您最终想用这个匹配做什么?您想根据它们在表格与控件矩阵中的位置将它们的标题更改为产品名称吗?在那之后你打算如何使用它们?你知道,我想,这个匹配是无法保存的。它仅对表格工作寿命有效。如果您选中,让我们说出标题为“Product22”的复选框,您要选择第二行的“Prod 2”吗?
  • @FaneDuru 作为第一步,你是对的。我想根据它们在表格与控件矩阵中的位置将它们的标题更改为产品名称。请在下面查看我的解决方案并告诉我您的想法。其次,勾选任何值/复选框都需要保存在工作表中,理想情况下,采用以下格式:指示 - 产品。希望它现在更有意义。谢谢!
  • 您没有说明“seg_l_selInd_”的含义。我知道匹配将根据控件标题完成。 “_”字符后的第一个数字表示产品所在的行,第二个表示列。但即使忘记了这方面,我问你想要完成什么。您将如何使用每个控件(新)标题以使其引用特定产品?我想有可能在不同的位置存在相同的产品名称。这个假设是否正确。即使没有,你打算如何在讨论中使用匹配?
  • 例如讨论中的匹配是在Form Initialization事件期间完成的,但是在匹配过程中一个Dictionary(表单模块级别的私有变量)具有通过控件Left之间的串联获得的key属性和控件 Top 属性和值对应产品所在的单元格地址。更改其值时,应根据字典键/值完成真正的匹配。

标签: excel vba


【解决方案1】:

请检查下一条路。我尝试以这种方式思考您的项目:

  1. 下一个示例中的表单必须命名为frmChkBox。表单上的复选框将具有“CheckBox11”、“CheckBox12”等名称,“CheckBox”字符串后的第一个数字为行,下一个为列。如果您意识到您的实际情况将超过行号的一位数字,它们可以用“_”或其他东西分隔。您还可以在 flay 上创建复选框。

一个。请在表单代码模块中粘贴下一行代码:

Option Explicit

Private ChkBColl As New Collection
Private ChkB() As New ChkBoxChClss

Private Sub UserForm_Initialize()
   Dim ws As Worksheet, rng As Range, iRow As Long, iCol As Long
   Dim ctrl As MSForms.Control, ext As String, arrUsed, k As Long
   
   ReDim ChkB(32)
   ReDim arrUsed(Me.Controls.count)
   Set ws = Sheets("INDICATION-PRODUCT")
   Set rng = ws.Range("B2:E9")
   For iRow = 1 To 8
        For iCol = 1 To 4
            For Each ctrl In Me.Controls
                If TypeOf ctrl Is MSForms.CheckBox Then
                    If IsError(Application.Match(ctrl.Caption, arrUsed, 0)) Then
                        ext = Right(ctrl.Caption, Len(ctrl.Caption) - 8)
                        If left(ext, 1) = iRow And Right(ext, 1) = iCol Then
                            ctrl.Tag = rng.cells(iRow, iCol).Address
                            ctrl.Caption = rng.cells(iRow, iCol).Value
                            arrUsed(k) = ctrl.Caption: k = k + 1
                            ChkBColl.Add ctrl, ctrl.Name
                            Set ChkB(k).chkBEvent = ctrl
                        End If
                    End If
                End If
            Next
        Next iCol
   Next iRow
End Sub

Public Sub DoSomething(chk As MSForms.CheckBox)
   Dim ws As Worksheet
   
   Set ws = Sheets("INDICATION-PRODUCT"): ws.Activate
   If chk.Value = True Then
        ws.Range(chk.Tag).Select 'do whatever needed with the cell...
   Else
        ws.Range("A1").Select
   End If
End Sub

每个复选框Tag 都会收到相关联的单元格地址。

为了自动为它们分配相同的事件,将创建一个简单的类包装器(名为“ChkBoxChClss”)。它将识别单击的复选框并将对象发送到表单子,根据需要在其中进行处理。请在类中粘贴下一个代码:

Option Explicit

Public WithEvents chkBEvent As MSForms.CheckBox

Private Sub chkBEvent_Change()
    frmChkBox.DoSomething chkBEvent
End Sub

您可以使用Public Sub DoSomething 来处理被单击的复选框。现在,点击一个复选框,如果它的值为True,对应的单元格将被选中。如果False,将选择“A1”单元格。你可以为所欲为。

【讨论】:

  • 这看起来很棒!谢谢你的帮助,真的很感激。 :)
  • @soraia635:很高兴我能帮上忙!但是以编程方式即时创建所有必要的复选框可能会很有趣。以相同的形式Initialize 事件。他们也可能收到相同的常见事件。通过这种方式,无需手动创建和命名特定范围的复选框,它们的数量不再重要。当然,代码一定要稍微适配一下……
【解决方案2】:

我终于解决了!

我的工作表上的表格(图 1)具有与我的用户表单上的指示值相对应的指示列。每种适应症都有几种产品。

我希望我的工具尽可能灵活,因此我需要匹配指示名称,并且对于我的用户表单中的每个复选框,我将从表中获取它的名称。

例如:指示 A,Prod 1 = Prod 1 (Checkbox.Name = Cell(x,y))

这是我正在使用的代码:

Dim code_ind As String
Dim sel_ind As String
Dim chkbx As Control
Dim labx As Control
Dim i As Integer
Dim j As Integer
Dim col_value As Integer
Dim row_value As Integer

For i = 1 To 8

Set chkbx = Me.Controls("seg_l_selInd_" & i)
sel_ind = tWb.Worksheets("INDICATION-PRODUCT").Columns(2).Find(what:=chkbx)

If chkbx = sel_ind Then
    col_value = 0
    While tWb.Worksheets("INDICATION-PRODUCT").Cells(i + 3, 3 + col_value) <> ""
    For j = 1 To 4
        
    Set labx = Me.Controls("seg_cb_selInd_" & i & j)
    labx.Caption = tWb.Worksheets("INDICATION-PRODUCT").Cells(i + 3, 3 + col_value)
    col_value = col_value + 1
    Next j
    Wend
End If
Next i

这对你有意义吗? 有什么办法可以让我的代码更灵活?例如,我假设有 8 个适应症(i = 1 到 8),但实际上未来可能会有更多。

【讨论】:

  • 在命名您的产品复选框时,您应该在ij 之间使用分隔符,否则如果您得到>10 个指示,您可能会遇到问题。
  • 最灵活的方法是完全从工作表构建表单内容 - 这样您就不需要保持表单和表格同步。例如见stackoverflow.com/questions/15530443/…
  • @TimWilliams 因此不会在用户表单中已有复选框,而是根据工作表上的内容添加它们。那正确吗?这听起来像是一个更好的主意。谢谢!
  • 是的 - 它有点复杂,但会更灵活且更易于维护。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-28
  • 2018-11-03
  • 2019-10-21
  • 2017-12-19
  • 2016-02-23
  • 1970-01-01
相关资源
最近更新 更多