Excel VBA - 创建一个带有多个组合框的动态用户窗体,并将所有组合框的值存储在一个数组中并对其进行排序
Excel VBA - Creating a dynamic userform with multiple combo boxes and storing the values of all combo boxes in one array and sorting through it
我正在 excel 2007 年创建一个用户窗体,它具有 6x6 组合框排列。最后一行和最后一列是 'all up' 框,它们的值应该基于它们各自的 rows/columns。剩下的 25 (5x5) 个组合框有 3 个值(红色、琥珀色、绿色),当用户选择一个值时,组合框显示该值并且背景用所选值着色(我通过创建一个函数来做到这一点在一个模块中并在每个 combobox_change()) 中调用它。
我在编码最后一行和最后一列框时遇到问题。基本上,如果说第 1 行,即使有一个 'Red',第 1 行 (1,6) 的最后一个框应该自动变为红色。如果没有红色,但是有一个'amber',那么最后一个框应该变成'amber'。如果有'red'和'amber',则应优先考虑'red'。列也有类似的逻辑。
到目前为止我尝试过的:
在用户表单代码中:
Private Sub Txt_Score_1_1_Change() 'This is for row 1 column 1 on the matrix'
Call ScoreChange.ScoreChange("Txt_Score_1_1")
模块内:
Public Sub ScoreChange(ctrlName As String)
If Scorecard.Controls(ctrlName).Value = "R" Then
Scorecard.Controls(ctrlName).BackColor = vbRed
ElseIf Scorecard.Controls(ctrlName).Value = "G" Then
Scorecard.Controls(ctrlName).BackColor = vbGreen
ElseIf Scorecard.Controls(ctrlName).Value = "A" Then
Scorecard.Controls(ctrlName).BackColor = vbYellow
Else
Scorecard.Controls(ctrlName).BackColor = vbWhite
End If
For i = 1 To 5
For j = 1 To 5
If Scorecard.Controls("Txt_Score_" & i & "_" & j).Value <> "" Then
If Scorecard.Controls("Txt_Score_" & i & "_" & j).Value = "R" Then
Scorecard.Controls("Txt_Score_" & i & "_6").Value = "R"
Scorecard.Controls("Txt_Score_6_" & j).Value = "R"
ElseIf Scorecard.Controls("Txt_Score_" & i & "_" & j).Value = "A" Then
Scorecard.Controls("Txt_Score_" & i & "_6").Value = "A"
Scorecard.Controls("Txt_Score_6_" & j).Value = "A"
End If
End If
Next j
Next i
End Sub
上面的方法可以在更改时更改组合框的各个颜色,但对于 'total'/'all up' 框会分崩离析。
我认为要实现上述目标需要做的是,我需要编写一个代码来识别特定 row/column 的所有组合框何时都已填充,然后将这些值存储在一个数组,并在数组中识别最后一个框的值。
任何关于如何实现这一点的帮助将不胜感激。
此外,如果类似的内容已在其他地方发布,我深表歉意,但我做了很多研究但找不到任何东西。
谢谢。
我认为可能有一种更简单的方法来完成这项任务,当然还有一种更简单的方法来消耗所有 ComboBox_Change
事件。
如果我正确理解你的问题,你是说你有一个 5 x 5 'child' 组合框的矩阵。然后,您有 5 个 'parent' 控件根据行的 children 的选择而变化,还有 5 个 'parent controls' 对列的 children 进行相同的选择。
因此,您可以做的是创建两个 classes。我称它们为 clsChild
和 clsParent
。 child class 捕获更改事件,然后通知行和列 parent 已发生更改。 parent class 包含其 children 的列表,并根据 children 的选择运行着色规则。
根据规则,我创建了一个 Enum
你的颜色,其中红色最低,白色最高,所以你只需选择任何 'score' 中最低的 'score' =52=]ren 为 parent 控件着色。
对于组合框,我保留了与您的 post 相同的命名约定,但我不明白为什么 'parent' 控件是组合框 - 当然您不希望用户是能改变他们吗?然后我冒昧地使用命名约定 Lbl_Score_R1 ... R5
行和 Lbl_Score_C1 ... C5
列命名约定 Labels
。
这种方法的美妙之处在于,你只需要将children和parent之间的关系绑定一次,然后简单地传递它们之间的控制权objects。这将避免每次发生更改事件时都必须进行笨拙的字符串操作。
那么,代码...
我。插入一个新的 class 并将其命名为 clsChild
。添加以下代码:
Option Explicit
Private WithEvents mCtrl As MSForms.ComboBox
Private mMum As clsParent
Private mDad As clsParent
Private mLight As Lights
Public Property Set Mum(val As clsParent)
Set mMum = val
Set mMum.ChildInLine = Me
End Property
Public Property Set Dad(val As clsParent)
Set mDad = val
Set mDad.ChildInLine = Me
End Property
Public Property Set Ctrl(val As MSForms.ComboBox)
Set mCtrl = val
With mCtrl
.List = Array("R", "A", "G", "W")
.ListIndex = 3
End With
End Property
Public Property Get Light() As Lights
Light = mLight
End Property
Private Property Let Light(val As Lights)
mLight = val
With mCtrl
Select Case mLight
Case Lights.Red: .BackColor = vbRed
Case Lights.Amber: .BackColor = vbYellow
Case Lights.Green: .BackColor = vbGreen
Case Lights.White: .BackColor = vbWhite
End Select
End With
If Not mMum Is Nothing Then mMum.ConsumeChildChanged
If Not mDad Is Nothing Then mDad.ConsumeChildChanged
End Property
Private Sub mCtrl_Change()
Select Case mCtrl.Value
Case Is = "R": Light = Red
Case Is = "A": Light = Amber
Case Is = "G": Light = Green
Case Else: Light = White
End Select
End Sub
二。插入另一个新的 class 并将其命名为 clsParent
并添加以下代码:
Option Explicit
Private mCtrl As MSForms.Label
Private mChildren As Collection
Private mLight As Lights
Public Property Set Ctrl(val As MSForms.Label)
Set mCtrl = val
Set mChildren = New Collection
End Property
Public Property Set ChildInLine(val As clsChild)
mChildren.Add val
End Property
Public Sub ConsumeChildChanged()
Dim lowest As Lights
Dim oChild As clsChild
lowest = White
For Each oChild In mChildren
With oChild
If .Light < lowest Then
lowest = .Light
End If
End With
Next
Light = lowest
End Sub
Private Property Get Light() As Lights
Light = mLight
End Property
Private Property Let Light(val As Lights)
mLight = val
With mCtrl
Select Case mLight
Case Lights.Red: .BackColor = vbRed
Case Lights.Amber: .BackColor = vbYellow
Case Lights.Green: .BackColor = vbGreen
Case Else: .BackColor = vbWhite
End Select
End With
End Property
三。在任何 Module
的顶部添加以下内容:
Public Enum Lights
Red
Amber
Green
White
End Enum
四。最后将以下内容添加到您的 UserForm
代码中:
Option Explicit
Private mMum(1 To 5) As clsParent
Private mDad(1 To 5) As clsParent
Private mChild(1 To 5, 1 To 5) As clsChild
Private Sub UserForm_Initialize()
Dim i As Integer, j As Integer
For i = 1 To 5
Set mMum(i) = New clsParent
Set mMum(i).Ctrl = Me.Controls("Lbl_Score_R" & i)
Set mDad(i) = New clsParent
Set mDad(i).Ctrl = Me.Controls("Lbl_Score_C" & i)
Next
For i = 1 To 5
For j = 1 To 5
Set mChild(i, j) = New clsChild
With mChild(i, j)
Set .Ctrl = Me.Controls("Txt_Score_" & i & "_" & j)
Set .Mum = mMum(i)
Set .Dad = mDad(j)
End With
Next
Next
End Sub
我正在 excel 2007 年创建一个用户窗体,它具有 6x6 组合框排列。最后一行和最后一列是 'all up' 框,它们的值应该基于它们各自的 rows/columns。剩下的 25 (5x5) 个组合框有 3 个值(红色、琥珀色、绿色),当用户选择一个值时,组合框显示该值并且背景用所选值着色(我通过创建一个函数来做到这一点在一个模块中并在每个 combobox_change()) 中调用它。
我在编码最后一行和最后一列框时遇到问题。基本上,如果说第 1 行,即使有一个 'Red',第 1 行 (1,6) 的最后一个框应该自动变为红色。如果没有红色,但是有一个'amber',那么最后一个框应该变成'amber'。如果有'red'和'amber',则应优先考虑'red'。列也有类似的逻辑。
到目前为止我尝试过的:
在用户表单代码中:
Private Sub Txt_Score_1_1_Change() 'This is for row 1 column 1 on the matrix'
Call ScoreChange.ScoreChange("Txt_Score_1_1")
模块内:
Public Sub ScoreChange(ctrlName As String)
If Scorecard.Controls(ctrlName).Value = "R" Then
Scorecard.Controls(ctrlName).BackColor = vbRed
ElseIf Scorecard.Controls(ctrlName).Value = "G" Then
Scorecard.Controls(ctrlName).BackColor = vbGreen
ElseIf Scorecard.Controls(ctrlName).Value = "A" Then
Scorecard.Controls(ctrlName).BackColor = vbYellow
Else
Scorecard.Controls(ctrlName).BackColor = vbWhite
End If
For i = 1 To 5
For j = 1 To 5
If Scorecard.Controls("Txt_Score_" & i & "_" & j).Value <> "" Then
If Scorecard.Controls("Txt_Score_" & i & "_" & j).Value = "R" Then
Scorecard.Controls("Txt_Score_" & i & "_6").Value = "R"
Scorecard.Controls("Txt_Score_6_" & j).Value = "R"
ElseIf Scorecard.Controls("Txt_Score_" & i & "_" & j).Value = "A" Then
Scorecard.Controls("Txt_Score_" & i & "_6").Value = "A"
Scorecard.Controls("Txt_Score_6_" & j).Value = "A"
End If
End If
Next j
Next i
End Sub
上面的方法可以在更改时更改组合框的各个颜色,但对于 'total'/'all up' 框会分崩离析。
我认为要实现上述目标需要做的是,我需要编写一个代码来识别特定 row/column 的所有组合框何时都已填充,然后将这些值存储在一个数组,并在数组中识别最后一个框的值。
任何关于如何实现这一点的帮助将不胜感激。
此外,如果类似的内容已在其他地方发布,我深表歉意,但我做了很多研究但找不到任何东西。
谢谢。
我认为可能有一种更简单的方法来完成这项任务,当然还有一种更简单的方法来消耗所有 ComboBox_Change
事件。
如果我正确理解你的问题,你是说你有一个 5 x 5 'child' 组合框的矩阵。然后,您有 5 个 'parent' 控件根据行的 children 的选择而变化,还有 5 个 'parent controls' 对列的 children 进行相同的选择。
因此,您可以做的是创建两个 classes。我称它们为 clsChild
和 clsParent
。 child class 捕获更改事件,然后通知行和列 parent 已发生更改。 parent class 包含其 children 的列表,并根据 children 的选择运行着色规则。
根据规则,我创建了一个 Enum
你的颜色,其中红色最低,白色最高,所以你只需选择任何 'score' 中最低的 'score' =52=]ren 为 parent 控件着色。
对于组合框,我保留了与您的 post 相同的命名约定,但我不明白为什么 'parent' 控件是组合框 - 当然您不希望用户是能改变他们吗?然后我冒昧地使用命名约定 Lbl_Score_R1 ... R5
行和 Lbl_Score_C1 ... C5
列命名约定 Labels
。
这种方法的美妙之处在于,你只需要将children和parent之间的关系绑定一次,然后简单地传递它们之间的控制权objects。这将避免每次发生更改事件时都必须进行笨拙的字符串操作。
那么,代码...
我。插入一个新的 class 并将其命名为 clsChild
。添加以下代码:
Option Explicit
Private WithEvents mCtrl As MSForms.ComboBox
Private mMum As clsParent
Private mDad As clsParent
Private mLight As Lights
Public Property Set Mum(val As clsParent)
Set mMum = val
Set mMum.ChildInLine = Me
End Property
Public Property Set Dad(val As clsParent)
Set mDad = val
Set mDad.ChildInLine = Me
End Property
Public Property Set Ctrl(val As MSForms.ComboBox)
Set mCtrl = val
With mCtrl
.List = Array("R", "A", "G", "W")
.ListIndex = 3
End With
End Property
Public Property Get Light() As Lights
Light = mLight
End Property
Private Property Let Light(val As Lights)
mLight = val
With mCtrl
Select Case mLight
Case Lights.Red: .BackColor = vbRed
Case Lights.Amber: .BackColor = vbYellow
Case Lights.Green: .BackColor = vbGreen
Case Lights.White: .BackColor = vbWhite
End Select
End With
If Not mMum Is Nothing Then mMum.ConsumeChildChanged
If Not mDad Is Nothing Then mDad.ConsumeChildChanged
End Property
Private Sub mCtrl_Change()
Select Case mCtrl.Value
Case Is = "R": Light = Red
Case Is = "A": Light = Amber
Case Is = "G": Light = Green
Case Else: Light = White
End Select
End Sub
二。插入另一个新的 class 并将其命名为 clsParent
并添加以下代码:
Option Explicit
Private mCtrl As MSForms.Label
Private mChildren As Collection
Private mLight As Lights
Public Property Set Ctrl(val As MSForms.Label)
Set mCtrl = val
Set mChildren = New Collection
End Property
Public Property Set ChildInLine(val As clsChild)
mChildren.Add val
End Property
Public Sub ConsumeChildChanged()
Dim lowest As Lights
Dim oChild As clsChild
lowest = White
For Each oChild In mChildren
With oChild
If .Light < lowest Then
lowest = .Light
End If
End With
Next
Light = lowest
End Sub
Private Property Get Light() As Lights
Light = mLight
End Property
Private Property Let Light(val As Lights)
mLight = val
With mCtrl
Select Case mLight
Case Lights.Red: .BackColor = vbRed
Case Lights.Amber: .BackColor = vbYellow
Case Lights.Green: .BackColor = vbGreen
Case Else: .BackColor = vbWhite
End Select
End With
End Property
三。在任何 Module
的顶部添加以下内容:
Public Enum Lights
Red
Amber
Green
White
End Enum
四。最后将以下内容添加到您的 UserForm
代码中:
Option Explicit
Private mMum(1 To 5) As clsParent
Private mDad(1 To 5) As clsParent
Private mChild(1 To 5, 1 To 5) As clsChild
Private Sub UserForm_Initialize()
Dim i As Integer, j As Integer
For i = 1 To 5
Set mMum(i) = New clsParent
Set mMum(i).Ctrl = Me.Controls("Lbl_Score_R" & i)
Set mDad(i) = New clsParent
Set mDad(i).Ctrl = Me.Controls("Lbl_Score_C" & i)
Next
For i = 1 To 5
For j = 1 To 5
Set mChild(i, j) = New clsChild
With mChild(i, j)
Set .Ctrl = Me.Controls("Txt_Score_" & i & "_" & j)
Set .Mum = mMum(i)
Set .Dad = mDad(j)
End With
Next
Next
End Sub