【问题标题】:Populate a vba ComboBox with the values from the drop-down list of a cell使用单元格下拉列表中的值填充 vba ComboBox
【发布时间】:2020-12-10 19:45:31
【问题描述】:

我想用在特定单元格中找到的下拉值填充一个组合框,比如 C10。

C10 使用 Excel 的数据验证功能将可输入单元格的值限制为下拉列表。我想使用这个列表来填充 vba userForm 中的组合框。

目前我的方法是使用:

Range("C10").Validation.Formula1

这里有 3 个可以返回的任意示例:

  1. “=制作”
  2. "=INDIRECT(C9 & "_MK")"
  3. “0;1;2;3;4;5;6;7;8;9;10”

我的方法是对此进行评估并尝试将其形成一个可用范围,该范围可用于设置我的组合框的 RowSource 属性。但是,我无法解释所有可以退回的可行案例。

当然有一种简单的方法可以实现我想要的,而无需为每种情况编写异常代码。

这样做的正确方法是什么?

【问题讨论】:

  • 不清楚这3个例子...首先,为什么是“arbitrari”?他们不是你的潜在案例吗?那么,“Makes”应该是一个命名范围(作为一个列表,包含更多单元格)吗? C9 &_MK 应该表示什么?通过“C9”单元格值和“_MK”之间的连接获得的另一个命名范围?应该列出最后一个案例吗?你真的把它当作“;”分开?通常,VBA 只使用逗号之类的分隔符,与本地化无关...
  • 它是讨论中的ComboBox 表单类型吗?如果是,是 Form 还是 ActiveX 类型?
  • 你必须在 proc 中单独处理它。这并不难:)
  • 你没有回答我的澄清问题...请测试我的答案代码,处理 ActiveX 类型的组合和(理论上)任何类型的 DropDown Validation.Formula1...

标签: excel vba combobox


【解决方案1】:

但是,我无法解释所有可以退回的可行案例。

您必须单独考虑。没有直接的方法可以获取这些值。

这是我编写的快速代码GetDVList(),它将处理您的所有 3 个场景。

下面的代码将返回一个数组中的数据验证列表的值,您可以从中填充组合框。我已经对代码进行了注释,因此您理解它应该没有问题,但如果您这样做了,只需询问即可。

这是你正在尝试的吗?

Option Explicit

Sub Sample()
    Dim rng As Range
    Dim i As Long
    Dim cmbArray As Variant
    
    '~~> Change this to the relevant sheet and range
    Set rng = Sheet1.Range("A1")
    
    '~~> Check if range has data validation
    On Error Resume Next
    i = rng.SpecialCells(xlCellTypeSameValidation).Count
    On Error GoTo 0
    
    '~~> If no validation found then exit sub
    If i = 0 Then
        MsgBox "No validation found"
        Exit Sub
    End If
    
    '~~> The array of values
    cmbArray = GetDVList(rng)
    
    '~~> You can transfer these values to Combobox
    For i = LBound(cmbArray) To UBound(cmbArray)
        Debug.Print cmbArray(i)
    Next i
End Sub

Function GetDVList(rng As Range) As Variant
    Dim tmpArray As Variant
    Dim i As Long, rw As Long
    Dim dvFormula As String
    
    dvFormula = rng.Validation.Formula1
    
    '~~> "=Makes"
    '~~> "=INDIRECT(C9 &_MK)"
    If Left(dvFormula, 1) = "=" Then
        dvFormula = Mid(dvFormula, 2)
        
        rw = Range(dvFormula).rows.Count
        
        ReDim tmpArray(1 To rw)
        
        For i = 1 To rw
            tmpArray(i) = Range(dvFormula).Cells(i, 1)
        Next i
    '~~> "0;1;2;3;4;5;6;7;8;9;10"
    Else
        tmpArray = Split(dvFormula, ",") '~~> Use ; instead of , if required
    End If

    GetDVList = tmpArray
End Function

【讨论】:

  • 感谢 Siddharth,但有数百个场景,而不仅仅是我列出的 3 个。我正在寻找更通用的解决方案
  • @Andrew M:没有冒犯,但你确定你知道你想要什么......?上述解决方案适用于任何范围和任何自定义列表。当然,您可以使用复杂的公式,如 =IF(A2=1,TestVal,ValVal) 甚至更多嵌套的 IF。不可能找到涵盖所有内容的解决方案。您必须将您的请求限制在合理的范围内,例如您在问题中请求的场景。在这种情况下,您应该将上述代码标记为已接受的答案
  • 上述解决方案不适用于一般情况。例如,适用于工作表但不适用于上述代码的 rng.Validation.Formula1 的一个可能值是: ;"";"");"'";"");"-";"");"(";"");")";"");".";"");"/ "; ""); ","; ""); ":"; ""); ";"; "")&"_MK")"。
  • 澄清一下,我没有编写验证规则 - 这是一个客户的工作簿,其中包含数百个验证规则编写不佳的单元格。我不能以任何方式更改床单。我仅限于仅在 VBA 中可以实现的目标。我只是在寻找最通用的解决方案
  • @AndrewM 没有通用的解决方案。对此没有通用的解决方案。就像我提到的那样,您必须分别处理每个案例。我已经向您展示了处理最基本、最常用的数据验证示例的方法。您将不得不对其进行调整。
【解决方案2】:

请测试下一个代码。它假设List Validation 公式只能返回Range 或列表(数组)。从理论上讲,它应该根据Range 或列表来评估任何公式并提取它返回的内容:

Sub comboListValidation()
 Dim cel As Range, arr, arrV
 Dim cb As OLEObject  'sheet ActiveX combo
 
 Set cb = ActiveSheet.Shapes("ComboBox1").OLEFormat.Object
 
 Set cel = ActiveCell 'instead of active cell you can use what you need
                      'even a cell resulted from iteration between `sameValidation` range
 
 arrV = isCellVal(cel) 'check if chell has validadion (and DropDown type)
 If Not arrV(0) Then
    MsgBox "No validation for cell """ & cel.Address & """.": Exit Sub
 ElseIf Not arrV(1) Then
    MsgBox "cell """ & cel.Address & """ has validation but not DropDown type.": Exit Sub
 End If
 
 arr = listValidation_Array(cel)
 
 With cb.Object
    .Clear      'clear the existing items (if any)
    .list = arr 'load the combo using arr
 End With
 MsgBox "Did it..."
End Sub

Private Function listValidation_Array(cel As Range) As Variant
  Dim strForm As String, rngV As Range, strList As String, arr

  strForm = cel.Validation.Formula1         'extract Formula1 string
  On Error Resume Next
   Set rngV = Application.Evaluate(strForm) '!!!try setting the evaluated range!!!
   If Err.Number = 424 Then 'if not a Range, it must be a list (usually, comma separated)
        Err.Clear: On Error GoTo 0
        listValidation_Array = Split(Replace(strForm, ";", ","), ",") 'treat the ";" sep, too
   Else
        On Error GoTo 0
        listValidation_Array = rngV.Value   'extract the array from range
   End If
End Function

Function isCellVal(rng As Range) As Variant
 Dim VType As Long
 Dim boolValid As Boolean, boolDropDown As Boolean
 
 On Error Resume Next
  VType = rng.Validation.Type 'check if validation exists
 On Error GoTo 0

 If VType >= 1 Then           'any validation type
     boolValid = True
     If VType = 3 Then boolDropDown = True 'dropDown type
 End If
 ReDim arr(1) : arr(0) = boolValid: arr(1) = boolDropDown
 isCellVal = arr
End Function

【讨论】:

    猜你喜欢
    • 2015-07-14
    • 1970-01-01
    • 2020-07-24
    • 1970-01-01
    • 2017-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多