这是我使用Excel VBA的第二天,我必须在一些同事失败后完成明天报告所需人力的申请。到目前为止,我必须阅读数百个教程并观看数十个视频以达到构建此应用程序的这一点,但我仍有一些问题需要解决。应用程序的想法是拥有一个打开工作簿后打开的用户窗体。分别有5个cobmobox用于选择标准(功能,位置,技术,工作模式和操作条件)。第二个组合框依赖于第一个和第三个依赖于第二个。第4和第5个依赖于第一个组合框,它工作正常。问题在于第3个组合框,因为它显示了所有选项,无论第2个组合框中的选择如何,因为案例选择仅读取数字!
以下是代码:
Private Sub ComboBox1_Change()
Dim index As Integer
index = ComboBox1.ListIndex
ComboBox2.Clear
Select Case index
Case Is = 0
With ComboBox2
.AddItem "Location 1"
.AddItem "Location 2"
.AddItem "Location 3"
.AddItem "Location 4"
End With
Case Is = 1
With ComboBox2
.AddItem "Location 1"
.AddItem "Location 2"
.AddItem "Location 3"
End With
Case Is = 2
With ComboBox2
.AddItem "Location 1"
.AddItem "Location 2"
.AddItem "Location 3"
End With
Case Is = 3
With ComboBox2
.AddItem "Location 1"
.AddItem "Location 2"
.AddItem "Location 3"
.AddItem "Location 4"
End With
Case Is = 4
With ComboBox2
.AddItem "Location 1"
.AddItem "Location 2"
.AddItem "Location 3"
.AddItem "Location 4"
End With
End Select
ComboBox4.Clear
Select Case index
Case Is = 0
With ComboBox4
.AddItem "8 Hours"
.AddItem "12 Hours"
End With
End Select
ComboBox5.Clear
Select Case index
Case Is = 0
With ComboBox5
.AddItem "Low Speed"
.AddItem "Normal Speed"
.AddItem "High Speed"
End With
Case Is = 2
With ComboBox5
.AddItem "Drips"
.AddItem "Pivots"
End With
End Select
End Sub
Private Sub ComboBox2_Change()
Dim index As Integer
index = ComboBox2.ListIndex
ComboBox3.Clear
Select Case index
Case Is = 0
With ComboBox3
.AddItem "Line 1"
.AddItem "Line 2"
.AddItem "Line 3"
.AddItem "Line 4"
.AddItem "Line 5"
End With
Case Is = 1
With ComboBox3
.AddItem "Line 1"
.AddItem "Line 2"
.AddItem "Line 3"
.AddItem "Line 4"
End With
Case Is = 2
With ComboBox3
.AddItem "Line 1"
.AddItem "Line 2"
End With
Case Is = 3
With ComboBox3
.AddItem "Line 1"
.AddItem "Line 2"
.AddItem "Line 3"
.AddItem "Line 4"
End With
End Select
End Sub
Private Sub UserForm_Initialize()
With ComboBox1
.AddItem "Function 1"
.AddItem "Function 2"
.AddItem "Function 3"
.AddItem "Function 4"
.AddItem "Function 5"
End With
End Sub
提前致谢
答案 0 :(得分:1)
我认为“我必须完成明天报告所需人力的申请”,即使您没有相关经验,也意味着您的老板希望您现在创建一个宏。我很高兴你尝试了很多教程,但没有替代练习。
为了测试你的代码,我创建了一个新的工作簿,其中包含一个新的用户表单,我在其中创建了五个组合框,我保留了默认名称。我复制了适合我的代码。根据ComboBox2中的选择,我在ComboBox3中获得了不同的选项。您需要更加具体地了解未按预期工作的内容。
但是,我会建议一些改变。你正在截止日期,所以这似乎是一个坏主意,但我的经验是,我建议的改变将节省时间。它们今天可以节省时间,因为更改将使您更容易调试宏。下周,当你的老板带回一长串的变化时,他们肯定会节省时间。
组合框允许用户键入自己的值。列表框类似于组合框,但用户只能从提供的选项中进行选择。我不记得每个使用组合框,因为我从来没有需要功能,虽然我可以理解它可能在适当的情况下有用。无论如何我更喜欢列表框,因为如果框足够大,选项总是可见的。也许有一个我从未发现过的技巧但我只能在单击框中看到组合框中的选项。
我删除了五个组合框,并用五个列表框替换它们,每个列表框大约五行,这样所有选项都可见。我将ListBox1
重命名为ComboBox1
,将ListBox2
重命名为ComboBox2
,依此类推。我不推荐这个,但这意味着我可以不改变你的代码。我可以单击box1中的选项,然后查看其他框中的选项。再次单击并查看另一组选项。正如我所说,你的代码看起来像你想要的那样。
然后我重命名了您的框:lstFunction
,lstLocation
,lstTechnology
,lstPattern
和lstConditions
。我记得当有一个三个字符前缀时,表明所有变量的类型都是常见的。这种做法在很大程度上已经因变量而消失,但对于用户表单控件而言并非如此我在这里使用它们是因为Function
是一个保留字,不能用作名称。我在代码中使用全局替换( Ctrl + H)将ComboBox1
替换为lstFunction
,依此类推。
有意义的名称的优点是代码更具可读性。你可能还记得Box3今天是技术,但是你会记得当你回到这个宏时是六个月还是十二个月?
我已将Integer
替换为Long
。 Integer
定义了一个16位,两个字节的变量,它可以保存-32,768到32,767范围内的值。当VBA首次推出时,这很好,但现在有两个主要的缺点。 (1)范围对于今天的Excel来说太小了。 (2)16位数需要在32位和64位计算机上进行特殊(慢速)处理。
最后,我将index (= ComboBox1.ListIndex)
替换为ComboBox1.Value
。您似乎认为Case
仅适用于数字。这不是真的。说实话,我更喜欢从隐藏的工作表中获取这些值,因为我发现工作表比代码更容易维护,但也许你应该把它留到下周。
这是我的最终代码:
Option Explicit
Private Sub lstFunction_Change()
Dim index As Long
index = lstFunction.ListIndex
lstLocation.Clear
Select Case lstFunction.Value
Case Is = "Function 1"
With lstLocation
.AddItem "Location 1"
.AddItem "Location 2"
.AddItem "Location 3"
.AddItem "Location 4"
End With
Case Is = "Function 2"
With lstLocation
.AddItem "Location 1"
.AddItem "Location 2"
.AddItem "Location 3"
End With
Case Is = "Function 3"
With lstLocation
.AddItem "Location 1"
.AddItem "Location 2"
.AddItem "Location 3"
End With
Case Is = "Function 4"
With lstLocation
.AddItem "Location 1"
.AddItem "Location 2"
.AddItem "Location 3"
.AddItem "Location 4"
End With
Case Is = "Function 5"
With lstLocation
.AddItem "Location 1"
.AddItem "Location 2"
.AddItem "Location 3"
.AddItem "Location 4"
End With
End Select
lstPattern.Clear
Select Case lstFunction
Case Is = "Function 1"
With lstPattern
.AddItem "8 Hours"
.AddItem "12 Hours"
End With
End Select
lstConditions.Clear
Select Case lstFunction
Case Is = "Function 1"
With lstConditions
.AddItem "Low Speed"
.AddItem "Normal Speed"
.AddItem "High Speed"
End With
Case Is = "Function 3"
With lstConditions
.AddItem "Drips"
.AddItem "Pivots"
End With
End Select
End Sub
Private Sub lstLocation_Change()
Dim index As Long
index = lstLocation.ListIndex
lstTechnology.Clear
Select Case lstLocation.Value
Case Is = "Location 1"
With lstTechnology
.AddItem "Line 1"
.AddItem "Line 2"
.AddItem "Line 3"
.AddItem "Line 4"
.AddItem "Line 5"
End With
Case Is = "Location 2"
With lstTechnology
.AddItem "Line 1"
.AddItem "Line 2"
.AddItem "Line 3"
.AddItem "Line 4"
End With
Case Is = "Location 3"
With lstTechnology
.AddItem "Line 1"
.AddItem "Line 2"
End With
Case Is = "Location 4"
With lstTechnology
.AddItem "Line 1"
.AddItem "Line 2"
.AddItem "Line 3"
.AddItem "Line 4"
End With
End Select
End Sub
Private Sub UserForm_Initialize()
With lstFunction
.AddItem "Function 1"
.AddItem "Function 2"
.AddItem "Function 3"
.AddItem "Function 4"
.AddItem "Function 5"
End With
End Sub
答案 1 :(得分:0)
我创建了一个空白工作簿,并在您呈现时运行代码。我对ComboBox3没有任何问题,如下图所示。
答案 2 :(得分:0)
在我的第一个回答中,我说“老实说,我更愿意从隐藏的工作表中获取这些值,因为我发现工作表比代码更容易维护,但也许你应该把它留到下周。”你的问题是关于{ {1}}声明表明您对目前的做法不满意。我同意那种不快乐;获得这样的代码是正确的,并将其作为新选项进行维护并引入新链接充其量是困难的,几乎是不可能的。
我发现在工作表中定义和维护此类链接更容易。尽管工作表是隐藏的,但它可能是最好的,尽管它包含的信息并不是秘密。考虑:
If
行1到6和8到12各自定义一个表,该表将列A中指定的控制列表框的允许值链接到列B,C等中指定的从属列表框的允许值。
表格由A列中的空白单元格终止。
表格的第一行列出了列表框的名称。表的其余行列出了允许值之间的关系。列A包含控制列表框的所有允许值。例如,单元格A2到A6包含列表框 | A | B | C | D | E |
|-----------|-------------|-------------|----------|-------------|
1 |lstFunction|lstLocation |lstTechnology|lstPattern|lstConditions|
|-----------|-------------|-------------|----------|-------------|
2 |Function 1 |Location 1 | |8 Hours |Low Speed |
| |Location 2 | |12 Hours |Normal Speed |
| |Location 3 | | |High Speed |
| |Location 4 | | | |
|-----------|-------------|-------------|----------|-------------|
3 |Function 2 |Location 1 | | | |
| |Location 2 | | | |
| |Location 3 | | | |
|-----------|-------------|-------------|----------|-------------|
4 |Function 3 |Location 1 | | |Drips |
| |Location 2 | | |Pivots |
| |Location 3 | | | |
|-----------|-------------|-------------|----------|-------------|
5 |Function 4 |Location 1 | | | |
| |Location 2 | | | |
| |Location 3 | | | |
|-----------|-------------|-------------|----------|-------------|
6 |Function 5 |Location 1 | | | |
| |Location 2 | | | |
| |Location 3 | | | |
|-----------|-------------|-------------|----------|-------------|
7 | | | | | |
|-----------|-------------|-------------|----------|-------------|
8 |lstLocation|lstTechnology| | | |
|-----------|-------------|-------------|----------|-------------|
9 |Location 1 |Line 1 | | | |
| |Line 2 | | | |
| |Line 3 | | | |
| |Line 4 | | | |
| |Line 5 | | | |
|-----------|-------------|-------------|----------|-------------|
10|Location 2 |Line 1 | | | |
| |Line 2 | | | |
| |Line 3 | | | |
| |Line 4 | | | |
|-----------|-------------|-------------|----------|-------------|
11|Location 3 |Line 1 | | | |
| |Line 2 | | | |
|-----------|-------------|-------------|----------|-------------|
12|Location 4 |Line 1 | | | |
| |Line 2 | | | |
| |Line 3 | | | |
| |Line 4 | | | |
|-----------|-------------|-------------|----------|-------------|
的所有允许值。如果用户选择了列A中的值,则列B,C等中的单元列出了从属列表框的允许值。例如,如果用户选择单元格A2中的值(“功能1”),则单元格B2列出由换行符分隔的从属控件lstFunction
的四个允许值。如果单元格为空,例如C3,则从属控件没有允许的值。
请注意,空白单元格(例如,C2,D3和E5)表示在不重新加载的情况下清除从属控制。我注意到,如果您为lstLocation
选择新值,则虽然您已清除lstFunction
和lstTechnology
,但仍未清除lstPattern
。我怀疑这是一个错误。
我在上面的描述中说“列表框”,即使代码适用于组合框但我没有看到链接框的概念如何应用于组合框。如果用户为控制组合框输入新值,其依赖控件会发生什么?
可以定义的链接数量没有限制。我希望您同意这样的表比您编写的代码类型更容易创建和维护。处理此表的代码编写起来比当前代码更复杂。我将介绍的代码的优点包括:
要了解我的代码,您需要了解用户表单的Controls集合。将以下代码添加到lstConditions
例程中:
UserForm_Initialize()
使用我的表单,输出为:
Dim InxC As Long
For InxC = 0 To Controls.Count - 1
Debug.Print InxC & " " & TypeName(Controls(InxC))
With Controls(InxC)
Debug.Print " Name=" & .Name & " Top=" & .Top & _
" Left=" & .Left & " Height=" & .Height & _
" Width=" & .Width
End With
Next
Debug.Print "lstFunction " & TypeName(Controls("lstFunction"))
每个表单都有一个名为0 ListBox
Name=lstFunction Top=18 Left=18 Height=61.5 Width=102
1 ListBox
Name=lstLocation Top=18 Left=144 Height=66 Width=90
2 ListBox
Name=lstTechnology Top=18 Left=258 Height=66 Width=96
3 ListBox
Name=lstPattern Top=18 Left=378 Height=66 Width=96
4 ListBox
Name=lstConditions Top=18 Left=492 Height=66 Width=90
5 CommandButton
Name=btnExit Top=96 Left=18 Height=24 Width=72
lstFunction ListBox
的集合,其中包含该表单上的每个控件。我的代码循环显示每个控件的索引号的详细信息。我展示的细节是类型名称,名称,位置和大小,但控件的每个参数都可以通过这种方式访问。最后,我使用其名称显示控件的类型。
我想表明的是,我可以写Controls
或lstFunction.Value
而不是写Controls(0).Value
。这允许我为所有控件编写一个通用例程,而不是为每个控件编写特定代码。
您可能还没有遇到的另一个工具是整个工作表(仅部分)可以在一个语句中导入:
Controls("lstFunction").Value
Variable = Range.Value
必须为Variable
类型,并且必须指定Variant
以匹配您要导入的工作表区域。
我考虑过处理导入的工作表来构建数据,但我认为它不会带来任何好处。但是,我认为有必要确定每个子表(A1和A8)的开头,以便它们可以轻松找到。
在没有错过任何截止日期的风险的情况下,我建议您通过下面的代码完成与原始代码相同的代码。我避免解释VBA语句,因为一旦你知道它们存在就很容易查找。我解释每个代码块的目标。如有必要,请回答问题。
我的代码希望找到包含上面定义的链接表的工作表“链接”。它希望表单包含名为Range
,lstFunction
,lstLocation
,lstTechnology
和lstPattern
的列表框以及名为lstConditions
的命令按钮。您可以更改这些名称以符合您的要求。
btnExit