Excel VBA - 使用多个组合框创建动态用户表单,并将所有组合框的值存储在一个数组中并对其进行排序

时间:2016-08-05 14:01:18

标签: arrays excel-vba combobox userform vba

我在excel 2007上创建了一个具有6x6排列组合框的用户窗体。最后一行和最后一列是'all up'框,它们应该具有基于各自行/列的值。其余25(5x5)个组合框有3个值(红色,琥珀色,绿色),当用户选择一个值时,组合框显示该值,背景颜色为选中的值(我这样做是通过创建一个函数在一个模块中并在每个combobox_change()内调用它。

我在编写最后一行和列框时遇到问题。基本上,如果对于第1行说,甚至只有一个“红色”,第1行(1,6)上的最后一个框应该自动变为红色。如果没有红色,但有一个'琥珀色',最后一个方框应该变成'琥珀色'。如果有“红色”和“琥珀色”,则应优先考虑“红色”。列的类似逻辑也是如此。

到目前为止我尝试过:

在userform代码中:

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

上述方法可以在更改时更改组合框的各个颜色,但会在“总计”/“全部向上”框中分开。

我认为要实现上述目标需要做的是我需要编写一个代码来识别特定行/列的所有组合框何时被填充,然后将这些值存储在数组中,并识别在数组中,最后一个框的值。

如何实现这一目标的任何帮助将不胜感激。

此外,如果在其他地方发布了类似的内容,我会道歉,但我做了很多研究,找不到任何东西。

感谢。

1 个答案:

答案 0 :(得分:1)

我认为可能有一种更简单的方法来攻击这项任务,当然也是一种更简单的方式来消费所有ComboBox_Change事件。

如果我理解你的问题,你说你有一个5乘5'子'组合框的矩阵。然后,您有5个“父级”控件,这些控件根据行子项的选择而变化,5个“父级控件”对列的子项执行相同操作。

因此,您可以创建两个类。我称他们为clsChildclsParent。子类捕获更改事件,然后通知行和列父项已发生更改。父类包含其子项列表,并根据子项的选择运行着色规则。

就规则而言,我已经创建了Enum您的颜色,其中红色最低,白色最高,所以您只需将任何一个孩子的最低'得分'给父母着色控制。

我保留了与ComboBoxes的帖子相同的命名约定,但我不明白为什么'父'控件是Comboboxes - 当然你不希望用户能够更改它们?我冒昧地使用命名约Labels为行Lbl_Score_R1 ... R5和列Lbl_Score_C1 ... C5。{/ p>

这种方法的优点在于你只需要将孩子和父母之间的关系绑定一次,然后简单地在他们之间传递控制对象。这将避免每次发生更改事件时都必须进行笨拙的字符串操作。

所以,代码......

我。插入一个新类并将其命名为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

II。插入另一个新类并将其命名为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

III。在任何Module的顶部添加以下内容:

Public Enum Lights
    Red
    Amber
    Green
    White
End Enum

IV。最后将以下内容添加到您的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