2016-08-05 60 views
0

Ich erstelle ein Benutzerformular auf Excel 2007, das eine 6x6 Anordnung von Kombinationsfeldern hat. Die letzte Zeile und die letzte Spalte sind die 'all-up'-Felder, die basierend auf ihren jeweiligen Zeilen/Spalten einen Wert haben sollten. Die restlichen 25 (5 x 5) Kombinationsfelder haben 3 Werte (Rot, Gelb, Grün). Wenn ein Benutzer einen Wert auswählt, zeigt das Kombinationsfeld den Wert an und der Hintergrund wird mit dem ausgewählten Wert eingefärbt (durch Erstellen einer Funktion) in einem Modul und aufrufend in jedem combobox_change()).Excel VBA - Erstellen eines dynamischen Benutzerformulars mit mehreren Kombinationsfeldern und Speichern der Werte aller Kombinationsfelder in einem Array und Sortieren

Ich habe Probleme bei der Codierung der letzten Zeilen- und Spaltenfelder. Grundsätzlich, wenn für Zeile 1 gesagt wird, dass es sogar ein einzelnes "Rot" gibt, sollte das letzte Feld in Zeile 1 (1,6) automatisch rot werden. Wenn es kein Rot gibt, aber ein "Bernstein", sollte das letzte Feld "Bernsteinfarben" sein. Wenn "rot" und "gelb" vorhanden ist, sollte "rot" die Priorität erhalten. Eine ähnliche Logik für Spalten.

Was ich bisher versucht:

Innerhalb der Userform Code:

Private Sub Txt_Score_1_1_Change() 'This is for row 1 column 1 on the matrix' 
Call ScoreChange.ScoreChange("Txt_Score_1_1") 

Innerhalb eines Moduls:

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 

Die oben arbeitet, um die einzelnen Farben der Kombinationsfelder zu ändern wenn geändert, fällt aber für die "total"/"all up" Boxen auseinander.

Was ich denke, getan werden muss, um das obige zu erreichen, ist, dass ich einen Code schreiben muss, der erkennt, wenn alle Kombinationsfelder für eine bestimmte Zeile/Spalte gefüllt sind, und speichert diese Werte in einem Array und erkennt innerhalb des Arrays den Wert für die letzte Box.

Jede Hilfe, wie dies zu erreichen ist, wird geschätzt.

Auch Entschuldigung, wenn etwas ähnliches woanders gepostet wurde, aber ich habe viel recherchiert und konnte nichts finden.

Danke.

Antwort

1

Ich denke, es könnte einen einfacheren Weg, diese Aufgabe anzugreifen, und sicherlich eine einfachere Möglichkeit, alle ComboBox_Change Ereignisse zu konsumieren.

Wenn ich Ihre Frage richtig verstehe, sagen Sie, dass Sie eine Matrix von 5 von 5 'Kind' ComboBoxen haben. Sie haben dann 5 "übergeordnete" Steuerelemente, die sich basierend auf der Auswahl der untergeordneten Elemente der Zeilen ändern, und 5 "übergeordnete Steuerelemente", die dasselbe für die untergeordneten Elemente der Spalten tun.

Sie können also zwei Klassen erstellen. Ich habe sie clsChild und clsParent genannt. Die Kindklasse fängt das Änderungsereignis ein und benachrichtigt dann die Zeilen- und Spalteneltern, dass eine Änderung aufgetreten ist. Die Elternklasse enthält eine Liste ihrer Kinder und führt die Färbungsregeln basierend auf der Auswahl der Kinder aus.

In Bezug auf die Regeln habe ich eine Enum Ihrer Farben erstellt, wobei Rot am niedrigsten ist und Weiß am höchsten ist, also nehmen Sie einfach die niedrigste "Punktzahl" eines der Kinder, um die Elternkontrolle zu färben.

Ich habe die gleichen Namenskonventionen wie Ihre Post für die ComboBoxen beibehalten, aber ich sehe nicht, warum die "übergeordneten" Steuerelemente Comboboxen sind - sicherlich möchten Sie nicht, dass ein Benutzer sie ändern kann? Ich habe mir dann die Freiheit genommen, sie Labels mit der Namenskonvention Lbl_Score_R1 ... R5 für Reihen und Lbl_Score_C1 ... C5 für Spalten zu machen.

Das Schöne an dieser Methode ist, dass Sie die Beziehungen zwischen Kindern und Eltern nur einmal binden müssen und die Kontrollobjekte einfach zwischen ihnen übergeben. Dadurch vermeiden Sie, dass Sie bei jedem Auftreten eines Änderungsereignisses Ihre unbequeme Zeichenfolgenmanipulation ausführen müssen.

Also, der Code ...

i. Fügen Sie eine neue Klasse ein und nennen Sie sie clsChild. Fügen Sie den folgenden Code hinzu:

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. Legen Sie eine andere neue Klasse und nennen es clsParent und fügen Sie den folgenden Code ein:

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. An der Spitze jeder Module fügen Sie folgendes:

Public Enum Lights 
    Red 
    Amber 
    Green 
    White 
End Enum 

iv. Und schließlich fügen Sie folgendes Ihrem UserForm Code hinzu:

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 
+0

Vielen Dank dafür. Es wirkt wie ein Zauber. Obwohl ich keine Ahnung habe, was eigentlich los ist ... denke ich, ich muss etwas über Klassen lernen. – Programmingnovice20

+0

Froh, dass es für Sie funktioniert. Und ja, wenn Sie viel mit den Steuerelementen einer UserForm arbeiten, dann sollten Sie sich über die Klassen- und Ereignisbehandlung informieren, da diese Ihren Code wirklich vereinfachen können. Es ist nicht kompliziert und dauert nur etwa eine Stunde. Versuchen Sie hier für Anfänger: http://www.cpearson.com/excel/Events.aspx – Ambie