Excel 基于另一个中的选择从后续下拉列表中删除选项

Excel 基于另一个中的选择从后续下拉列表中删除选项,excel,vba,Excel,Vba,我的VBA表格中有三个下拉列表(cbo_fac1,cbo_fac2,cbo_fac3),每个下拉列表都从同一来源提取数据。但是我想在选择列表组上实现一个级联更新,这样当用户从一个选择列表中选择一个选项时,它就会从后续的选择列表中删除 例如,如果cbo_fac1具有以下选项: Blu-ray DVD Player Chalk board Computer Data projector Data projector trolley 并且用户从cbo_fac1中选择蓝光DVD播放机,然后接下来的两

我的VBA表格中有三个下拉列表(cbo_fac1cbo_fac2cbo_fac3),每个下拉列表都从同一来源提取数据。但是我想在选择列表组上实现一个级联更新,这样当用户从一个选择列表中选择一个选项时,它就会从后续的选择列表中删除

例如,如果cbo_fac1具有以下选项:

Blu-ray DVD Player
Chalk board
Computer 
Data projector
Data projector trolley
并且用户从cbo_fac1中选择
蓝光DVD播放机
,然后接下来的两个下拉菜单(cbo_fac2cbo_fac3)应该只有以下选项可用:

Chalk board
Computer 
Data projector
Data projector trolley
如果用户随后决定从cbo_fac2中选择
数据投影仪台车
,则下一个和最后一个下拉(cbo_fac3)应该只有以下选项可供选择:

Chalk board
Computer 
Data projector
当然,如果用户决定返回并更改他们的选项,那么这也应该反映出来。我将如何实现这一目标。这是我目前掌握的代码:

   For Each c_fac In ws_misc.Range("fac")
        With Me.cbo_fac1
        .AddItem c_fac.Value
        .List(.ListCount - 1, 1) = c_fac.Offset(0, 1).Value
         End With
        With Me.cbo_fac2
        .AddItem c_fac.Value
        .List(.ListCount - 1, 1) = c_fac.Offset(0, 1).Value
        End With
        With Me.cbo_fac3
        .AddItem c_fac.Value
        .List(.ListCount - 1, 1) = c_fac.Offset(0, 1).Value
        End With
      Next c_fac

提前谢谢

这花费的时间比我想象的要长。我以为会更容易:)

对于此解决方案,我将在VBA中使用用户定义的类型。请参见此示例:

将其放在一个模块中:

Option Explicit

Public Type listOptions
    name As String
    isUsed As Boolean
End Type
在userform上添加三个组合框。将组合框更改为名称:cbo_fac1、cbo_fac2、cbo_fac3

然后在userform后面添加以下代码:

Option Explicit

' options needs to be persisted throughout the life of the program
Dim options() As listOptions

Private Sub UserForm_Initialize()
    ' setup options
    Call getOptionsFromWorksheet("Sheet1")

    fillComboBoxWithOptions "cbo_fac1"
    fillComboBoxWithOptions "cbo_fac2"
    fillComboBoxWithOptions "cbo_fac3"
End Sub

Private Sub getOptionsFromWorksheet(ByRef wsName As String)
    Dim ws As Excel.Worksheet
    Set ws = ThisWorkbook.Worksheets(wsName)

    ' assuming data begins at A1
    Dim lastCell As Long
    Dim i As Long

    lastCell = ws.Cells.SpecialCells(xlCellTypeLastCell).Row

    ReDim options(lastCell - 1)

    For i = 1 To lastCell
        options(i - 1) = createOption(ws.Cells(i, 1).Value)
    Next
End Sub

Private Function createOption(ByRef theName) As listOptions
    Dim opt As listOptions
    opt.name = theName
    opt.isUsed = False
    createOption = opt
End Function


Private Sub cbo_fac1_AfterUpdate()
    Call resetSelectedOptions

    ' reset other combo boxes with options
    fillComboBoxWithOptions "cbo_fac2"
    fillComboBoxWithOptions "cbo_fac3"
End Sub

Private Sub cbo_fac2_AfterUpdate()
    Call resetSelectedOptions

    ' reset other combo boxes with options
    fillComboBoxWithOptions "cbo_fac1"
    fillComboBoxWithOptions "cbo_fac3"
End Sub

Private Sub cbo_fac3_AfterUpdate()
    Call resetSelectedOptions

    ' reset other combo boxes with options
    fillComboBoxWithOptions "cbo_fac1"
    fillComboBoxWithOptions "cbo_fac2"
End Sub

' Resets the combobox control with the available options
Private Sub fillComboBoxWithOptions(ByRef comboBoxName)
    Dim selectedItem As String

    ' get and store the selected item, if any,
    ' so we can re-select it after we clear it out and re-fill it
    If (Me.Controls(comboBoxName).ListIndex <> -1) Then
        selectedItem = Me.Controls(comboBoxName).List(Me.Controls(comboBoxName).ListIndex)
    End If

    Me.Controls(comboBoxName).Clear
    Dim i As Long
    For i = 0 To UBound(options)
        If (options(i).name = selectedItem) Then
            Me.Controls(comboBoxName).AddItem options(i).name
        ElseIf (Not options(i).isUsed) Then
            Me.Controls(comboBoxName).AddItem options(i).name
        End If
    Next

    ' re-select the item
    For i = 0 To Me.Controls(comboBoxName).ListCount - 1
        If (Me.Controls(comboBoxName).List(i) = selectedItem) Then
            Me.Controls(comboBoxName).ListIndex = i
            Exit For
        End If
    Next
End Sub

Private Sub resetSelectedOptions()
    Dim i As Long
    For i = 0 To UBound(options)
        options(i).isUsed = False
    Next

    ' Since the list index will not match the index of the options() array
    ' we have to loop through until we find a matching name and set
    ' the isUsed = True
    If (cbo_fac1.ListIndex <> -1) Then
        For i = 0 To UBound(options)
            If (options(i).name = cbo_fac1.List(cbo_fac1.ListIndex)) Then
                options(i).isUsed = True
                Exit For
            End If
        Next
    End If

    If (cbo_fac2.ListIndex <> -1) Then
        For i = 0 To UBound(options)
            If (options(i).name = cbo_fac2.List(cbo_fac2.ListIndex)) Then
                options(i).isUsed = True
                Exit For
            End If
        Next
    End If


    If (cbo_fac3.ListIndex <> -1) Then
        For i = 0 To UBound(options)
            If (options(i).name = cbo_fac3.List(cbo_fac3.ListIndex)) Then
                options(i).isUsed = True
                Exit For
            End If
        Next
    End If

End Sub
选项显式
“选项需要在项目的整个生命周期中保持不变
Dim options()作为列表选项
私有子用户表单_初始化()
'设置选项
调用GetOptions fromWorksheet(“Sheet1”)
使用选项“cbo\U fac1”填写ComboBox
使用选项“cbo\U fac2”填写ComboBox
使用选项“cbo\U fac3”填写ComboBox
端接头
私有子getOptionsFromWorksheet(ByRef wsName作为字符串)
将ws设置为Excel.Worksheet
设置ws=ThisWorkbook.Worksheets(wsName)
'假设数据从A1开始
暗淡的最后一个细胞一样长
我想我会坚持多久
lastCell=ws.Cells.SpecialCells(xlCellTypeLastCell).Row
重拨选项(lastCell-1)
对于i=1到最后一个单元格
options(i-1)=createOption(ws.Cells(i,1.Value)
下一个
端接头
私有函数createOption(ByRef theName)作为listOptions
Dim opt As列表选项
opt.name=名称
opt.isUsed=False
createOption=opt
端函数
私人次级cbo_fac1_AfterUpdate()
呼叫重置选择选项
'使用选项重置其他组合框
使用选项“cbo\U fac2”填写ComboBox
使用选项“cbo\U fac3”填写ComboBox
端接头
私人次级cbo_fac2_AfterUpdate()
呼叫重置选择选项
'使用选项重置其他组合框
使用选项“cbo\U fac1”填写ComboBox
使用选项“cbo\U fac3”填写ComboBox
端接头
私人次级cbo_fac3_更新后()
呼叫重置选择选项
'使用选项重置其他组合框
使用选项“cbo\U fac1”填写ComboBox
使用选项“cbo\U fac2”填写ComboBox
端接头
'使用可用选项重置组合框控件
私有子fillComboBoxWithOptions(ByRef ComboxName)
将selectedItem设置为字符串
'获取并存储所选项目(如果有),
“因此,我们可以在清除并重新填充后重新选择它
如果(Me.Controls(comboBoxName).ListIndex-1),那么
selectedItem=Me.Controls(comboBoxName).List(Me.Controls(comboBoxName).ListIndex)
如果结束
Me.Controls(comboBoxName).清除
我想我会坚持多久
对于i=0到UBound(选项)
如果(选项(i).name=selectedItem),则
控件(comboBoxName).AddItem选项(i).name
ElseIf(不使用选项(i)
控件(comboBoxName).AddItem选项(i).name
如果结束
下一个
'重新选择项目
对于i=0到Me.Controls(comboBoxName).ListCount-1
如果(Me.Controls(comboBoxName).List(i)=selectedItem),则
控件(comboBoxName).ListIndex=i
退出
如果结束
下一个
端接头
专用子重置SelectedOptions()
我想我会坚持多久
对于i=0到UBound(选项)
选项(i).isUsed=False
下一个
'因为列表索引与options()数组的索引不匹配
“我们必须循环,直到找到匹配的名称并设置
'isUsed=True
如果(cbo_fac1.ListIndex-1),则
对于i=0到UBound(选项)
如果(选项(i).name=cbo_fac1.List(cbo_fac1.ListIndex)),则
选项(i).isUsed=True
退出
如果结束
下一个
如果结束
如果(cbo_fac2.ListIndex-1),则
对于i=0到UBound(选项)
如果(选项(i).name=cbo_fac2.List(cbo_fac2.ListIndex)),则
选项(i).isUsed=True
退出
如果结束
下一个
如果结束
如果(cbo_fac3.ListIndex-1),则
对于i=0到UBound(选项)
如果(选项(i).name=cbo_fac3.List(cbo_fac3.ListIndex)),则
选项(i).isUsed=True
退出
如果结束
下一个
如果结束
端接头
这里的想法是,在每个组合框被选择一个值之后,它将使用AferUpdate事件重置其他组合框。它还考虑组合框是否已选择值

希望这有帮助

编辑:
我更改了代码以适应工作表中的数据。我将工作表命名为“Sheet1”(将其更改为您需要的任何内容),我假设在该工作表中,唯一的数据是您希望列出的项目列表(因此,工作表中没有标题,也没有任何其他数据)。

您没有说文本是在Hanks bro中的哪一列。我注意到您列出了选项,而不是从电子表格中取出它们。很抱歉,我的代码片段没有说明全部情况。我目前正在从电子表格中提取这些值。这会是个问题吗?以下是我的代码:没问题。这没什么大不了的,只是多了一点代码。