Excel vba根据组合框中的多个值从单元格中获取值

时间:2016-01-18 13:14:53

标签: excel vba excel-vba


我有一个excel文档,我想根据基于组合框的多个值从单元格中提取值。

第一个组合框包含“Teknik”栏中的所有值 第二个组合框包含“Kund”列中的所有值 第三个组合框包含“年”行,2016年,2017年的所有值...
Forth组合框包含1月至12月的所有月份

如果我选择
,我想提取值“Cust1”和“Demo” VoLTE - > Kund1 - > 2016年 - > 1月

enter image description here

Private Sub monthCombo_Change()

Dim ws As Worksheet

Dim yearFound As Range
Dim custFound As Range
Dim monFound As Range

'sheet
With Me.cmbSheet
    If .ListIndex = -1 Then Exit Sub
    Set ws = ActiveWorkbook.Sheets(.Text)
End With

'customer combo
With Me.custCombo
    If .ListIndex = -1 Then Exit Sub
    Set custFound = ws.Columns("C").Find(.Text, ws.Cells(ws.Rows.Count, "C"), xlValues, xlWhole)
End With

'year combo
With Me.yearCombo
    If .ListIndex = -1 Then Exit Sub
    Set yearFound = ws.Rows(3).Find(.Text, ws.Cells(3, ws.Columns.Count), xlValues, xlWhole)
End With
End Sub

我在想我应该首先找到客户,年份和月份,然后通过单元格进行迭代,但我在vba中没有任何线索是如何将所有变量绑定在一起以便在选择时上面我得到了正确的价值。

这个question帮助我将值连接到一个值。

1 个答案:

答案 0 :(得分:1)

我没有尝试创建任何符合您要求的代码,因此这是对如何开发该代码的描述。

我不清楚整理工作表会有所帮助。我会从你拥有的东西开始,但如果我后来认为它会有所帮助,我会保留整理的权利。

如果您不熟悉VBA,可能不熟悉ReDim。这个声明可以在VB.Net上找到,但我知道没有其他语言包含它,所以我认为它不适用于C#。

Dim X(1 to 5) As String

上面定义了一个固定大小的字符串数组,其中包含元素1到5.VBA允许您指定数组的下限。我认为C#没有。

Dim X() As String

上面指定了一个动态的字符串数组,我将在运行时调整大小,也许可以调整大小。

Dim X() As String
ReDim X(1 To 5)
ReDim X(1 To 10)
ReDim Preserve X(1 To 10)
  • Dim X() As String定义了X。
  • ReDim X(1 To 5)大小X用于保存元素1到5。
  • ReDim X(1 To 10)释放原始X以进行垃圾收集,并创建一个新的X来保存元素1到10.
  • ReDim Preserve X(1 To 10)创建一个新的X来保存元素1到10,在释放原始X以进行垃圾回收之前复制原始X中的值。

当有人事先不知道X需要多大时,你有时会在循环中看到ReDim Preserve X(1 To UBound(X)+1)。您可以想象这非常方便,但是如果循环足够大,它可能变得非常慢,通常不推荐使用。

我假设你没有大量的唯一值,所以放慢速度并不重要,所以我会从ReDim Preserve X(1 To UBound(X)+1)开始,但如果这会导致问题,请准备尝试不同的方法。

你说你有组合框。组合框允许用户输入自己的值,如果他们不喜欢其中一个。这在你的场景中毫无意义。您希望列表框与组合框实际上相同,而无需用户输入值。

我会使用范围,范围联盟和范围相交来控制所需细胞的选择。考虑一下这个演示宏:

Sub Demo()

  Const CellsPerSelection As Long = 2

  Dim RngColA As Range
  Dim RngColB As Range
  Dim RngYYMM As Range
  Dim RngSelected As Range
  Dim Cell As Range
  Dim Count As Long

  Set RngColA = Rows("5:49")
  Set RngColB = Union(Rows(8), Rows(40), Rows(55), Rows(80))
  Set RngYYMM = Union(Columns(5), Columns(6))

  Set RngSelected = Intersect(RngColA, RngColB, RngYYMM)

  If RngSelected Is Nothing Then
    Debug.Print "No intersect"
  Else
    Count = 0
    For Each Rng5 In RngSelected
      If Count = 0 Then
        Debug.Print "Pair:";
      End If
      Debug.Print " " & Rng5.Address;
      Count = Count + 1
      If Count = CellsPerSelection Then
        Debug.Print
        Count = 0
      End If
    Next
  End If

End Sub

我不想解释VBA。如果您不理解某个特定陈述,您应该能够轻松地查找它。但是如果有必要,请回答问题。我要解释的是这段代码的目标。

考虑:Set RngColA = Rows("5:49")。在真正的宏中,我会有一个这样的列表:

VoLTE     Rows("5:49")
XYZ       Rows("50:75")
UVW       Rows("76:100")

因此宏可以将选择“VoLTE”转换为范围Rows("5:49")。在这里,我刚刚将RngColA设置为此范围。

考虑Set RngColB = Union(Rows(8), Rows(40), Rows(55), Rows(80))。在这里,我将列表想象为:

Kund1     Union(Rows(8), Rows(40), Rows(55), Rows(80))
Kund2     Union(Rows(9), Rows(35), Rows(65), Rows(95))
Kund3     Union(Rows(12), Rows(70), Rows(100), Rows(105))

“Kund1”的值是从B列中包含“Kund1”的所有行的并集创建的范围。注意,我允许值“Kund1”在“VoLTE”中出现两次。我不知道这是否可行。如果不可能,您可以简化宏末尾的代码。

Set RngYYMM = Union(Columns(5), Columns(6))类似,但列出了2016年1月的专栏。

Set RngSelected = Intersect(RngColA, RngColB, RngYYMM)提取所选范围之间的重叠。这种重叠是$E$8:$F$8,$E$40:$F$40。如果“Kund1”只有一个值,则为$E$8:$F$8

底部的代码允许没有重叠。如果存在重叠,则会将RngSelected拆分为单元格对。我只是将地址输出到立即窗口,但您可以使用它来向用户显示值。

在使用此宏的等价物向用户显示值之前,您需要创建从中选择值的三个列表。

对于第一个列表,向下运行列A给出:

VoLTE     on row 5
XYZ       on row 50
UVW       on row 76

另外,您需要发现值为100的最后一行。这是创建列表所需的所有信息。

我会把这个列表保存在一个数组中。大多数语言都提供结构或结构。 VBA将它们称为用户类型,但这只是一个不同的名称。定义必须位于模块的顶部:

Type ValueRange
  Value As String
  Rng As Range
End Type

数组定义可以是全局的,通常在子例程中:

Dim ColA() As ValueRange
Dim ColB() As ValueRange
Dim YYMM() As ValueRange

希望以上有所帮助。