如何在VBA中创建动态列表?

时间:2017-01-21 04:44:49

标签: excel vba excel-vba

我有一张excel表。我想创建一个将在5个单元格中的列表。为简单起见,我们将列表中的项目称为(item1,item2,item3,item4,item5)。如果我从单元格1中选择“list1”,则其他列表中的项目内容应该变为(item2,item3,item4,item5)并且在加扰时;列表应该将数据重新包含在列表中。

我尝试了以下内容:

Sub PopulatingArrayVariable()
'PURPOSE: Dynamically Create Array Variable based on a Given Size

Dim myArray() As Variant
Dim DataRange As Range
Dim cell As Range
Dim x As Long

'Determine the data you want stored
 Set DataRange = ActiveSheet.UsedRange

'Resize Array prior to loading data
ReDim myArray(DataRange.Cells.Count)

'Loop through each cell in Range and store value in Array
For Each cell In DataRange.Cells
  myArray(x) = cell.Value
  x = x + 1
Next cell

End Sub

示例:

假设有3个单元格A,B,C。所有这些单元格都有这个列表(将其视为我们在数据验证或静态数组中看到的列表)。因此,我们的单元格将具有列表中的值,如(NY,NJ,LA)。一旦我们从单元格A中选择一个元素(NY),要在单元格B,C中显示的列表的其余元素应该是(NJ,LA)。如果任何其他单元格选择此NY,则它不应出现在单元格B,C中。

3 个答案:

答案 0 :(得分:0)

如果我选择" list1"那么很少会对你的意思感到困惑。从一个单元格1开始,其他列表中的项目内容应该变为(list2,list3,list4,list5)并且在加扰时;列表应该将数据重新包含在列表中。" ..但要编写一个子来填充一个单独的数组,其中使用的工作表范围非常接近 - 事实上我认为你的代码应该只用1个简单改变:

Sub PopulatingArrayVariable()
'PURPOSE: Dynamically Create Array Variable based on a Given Size

Dim myArray() As Variant
Dim DataRange As Range
Dim cell As Range
Dim x As Long

'Determine the data you want stored
 Set DataRange = ActiveSheet.UsedRange

'Resize Array prior to loading data
ReDim myArray(DataRange.Cells.Count)

'Loop through each cell in Range and store value in Array
For Each cell In DataRange.Cells
  x = x + 1
  myArray(x) = cell.Value
Next cell

End Sub

我会说几件事情,1)使用Option Explicit是一个好主意 - 它让我免于大量的编码错误,这些错误在我经过几个小时的难以理解的故障排​​除之后才可能找不到。 .. 2)如果你使用Option Explicit并且不能再使用For Each cell In DataRange.Cells语法,那么这将是如何重写sub:

Sub PopulatingArrayVariableVersion2()
'PURPOSE: Dynamically Create Array Variable based on a Given Size

Dim myArray() As Variant
Dim tempArr() As Variable 'Temp Array to read in data range
Dim DataRange As Range
Dim rowCounter As Long 'For looping through tempArr's Rows
Dim colCounter As Long 'For looping through tempArr's Cols
Dim arrWriter As Long 'Need additional variable to store the element of array to write to

'Determine the data you want stored
 Set DataRange = ActiveSheet.UsedRange

'Resize Array prior to loading data
ReDim myArray(DataRange.Cells.Count)
tempArr = DataRange 'Load in DataRange as array

'Loop through row,col in tempArr and store value in Array
For rowCounter = 1 To UBound(tempArr, 1)
    For colCounter = 1 To UBound(tempArr, 2)
        arrWriter = arrWriter + 1
        myArray(arrWriter) = tempArr(rowCounter, colCounter)
    Next
Next

End Sub

此外,我认为每次使用数组而不是从某个范围读取最终会更快 -

希望这有帮助, TheSilkCode

答案 1 :(得分:0)

好了,现在我看到你正在尝试做什么 - 你正在尝试使用其他工作表范围内的值填充单元格数据验证下拉列表...所以你是在正确的轨道但问题是数据验证实际上需要一个字符串,其元素以逗号分隔,而不是数组...所以最终的代码看起来像:

Public Sub setValidationList()
Dim targetCell As Range
Set targetCell = ThisWorkbook.Sheets(1).Range("A1")
With targetCell.Validation
    .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:=xlBetween, Formula1:=getValidationList
End With
End Sub

Public Function getValidationList() As String
Dim dataRange As Range
Dim listStr As String
Dim tempArr() As Variant 'Temp Array to read in data range
Dim rowCounter As Long 'For looping through tempArr's Rows
Dim colCounter As Long 'For looping through tempArr's Cols

Set dataRange = ThisWorkbook.Sheets("Sheet1").UsedRange
tempArr = dataRange

'Loop through row,col in tempArr and store value in Array
For rowCounter = 1 To UBound(tempArr, 1)
    For colCounter = 1 To UBound(tempArr, 2)
        listStr = listStr & IIf(listStr <> "", ",", "") & CStr(tempArr(rowCounter, colCounter))
    Next
Next
getValidationList = listStr
End Function

希望这有帮助, TheSilkCode

答案 2 :(得分:0)

已修改以添加GetRangeFromValidationFormula()功能代码(以前称为GetRange()

根据您在问题中添加的示例,您可以尝试在相关工作表代码窗格中添加以下代码:

Option Explicit

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim listRng As Range, validationRng As Range, cell As Range, cell2 As Range
    Dim changedValue As String

    Set listRng = Range("A1:A3") '<--| this are your "3 cells A, B, C"

    If Not Intersect(Target, listRng) Is Nothing Then
        changedValue = Target.value
        Set validationRng = GetRangeFromValidationFormula(Target.Validation.Formula1)

        Application.EnableEvents = False
        On Error GoTo ExitSub
        listRng.ClearContents
        For Each cell In listRng
            If cell.Address = Target.Address Then
                cell.value = changedValue
            Else
                For Each cell2 In validationRng
                    If listRng.Find(what:=cell2.value, LookIn:=xlValues, lookat:=xlWhole) Is Nothing And cell2.value <> changedValue Then
                        cell.value = cell2.value
                        Exit For
                    End If
                Next
            End If
        Next
    End If

ExitSub:
    Application.EnableEvents = True
End Sub


Function GetRangeFromValidationFormula(validationFormula As String) As Range
    Dim list As Variant
    list = VBA.Split(Replace(ActiveCell.Validation.Formula1, "=", ""), "!")

    If UBound(list) > 0 Then
        Set GetRange = Worksheets(list(0)).Range(list(1))
    Else
        Set GetRange = Range(list(0))
    End If
End Function
相关问题