ABOUT Visual Basic Programmieren Programmierung Download Downloads Tips & Tricks Tipps & Tricks Know-How Praxis VB VBA Visual Basic for Applications VBS VBScript Scripting Windows ActiveX COM OLE API ComputerPC Microsoft Office Microsoft Office 97 Office 2000 Access Word Winword Excel Outlook Addins ASP Active Server Pages COMAddIns ActiveX-Controls OCX UserControl UserDocument Komponenten DLL EXE
Diese Seite wurde zuletzt aktualisiert am 16.12.2002

Diese Seite wurde zuletzt aktualisiert am 16.12.2002
Aktuell im ABOUT Visual Basic-MagazinGrundlagenwissen und TechnologienKnow How, Tipps und Tricks rund um Visual BasicActiveX-Komponenten, Controls, Klassen und mehr...AddIns für die Visual Basic-IDE und die VBA-IDEVBA-Programmierung in MS-Office und anderen AnwendungenScripting-Praxis für den Windows Scripting Host und das Scripting-ControlTools, Komponenten und Dienstleistungen des MarktesRessourcen für Programmierer (Bücher, Job-Börse)Dies&Das...

Themen und Stichwörter im ABOUT Visual Basic-Magazin
Code, Beispiele, Komponenten, Tools im Überblick, Shareware, Freeware
Ihre Service-Seite, Termine, Job-Börse
Melden Sie sich an, um in den vollen Genuss des ABOUT Visual Basic-Magazins zu kommen!
Informationen zum ABOUT Visual Basic-Magazin, Kontakt und Impressum

Zurück...

Knoten im Zwischenzustand

Zurück...


Anzeige

(-hg) mailto:hg_tvwsemichecks@aboutvb.de

Eine CheckBox kann nicht nur die zwei Zustände "gesetzt" (vbChecked) und "nicht gesetzt" (vbUnchecked) annehmen, sondern sie kennt auch noch einen Zwischenzustand, bei dem die CheckBox zwar als gesetzt gilt, aber der Hintergrund (in der "klassischen" Windows-Farbgebung) grau eingefärbt erscheint. Dieser Zwischenzustand soll andeuten, dass die Einstellung von anderen Einstellungen abhängig ist - etwa dass nach- bzw. untergeordnete Einstellungen nicht vollständig gesetzt sind.

Die CheckBoxen eines TreeView-Steuerelements (wenn Sie dessen Eigenschaft "Checkboxes" auf True setzen), kennen einen solchen Zwischenzustand leider nicht, obwohl eine Baum-Struktur doch geradezu ein typischer Fall der Repräsentation von untergeordneten, abhängigen Optionen darstellt. Wenn Sie solche Zwischenzustände darstellen wollen, müssen Sie jedoch auf die eingebauten CheckBoxen des TreeViews verzichten und statt dessen die Symbole der Knoten entsprechend setzen. Die beim Klick auf einen Knoten anfallende Analyse, welcher Zustand für ihn angezeigt werden soll, können Sie mittels einiger weniger Hilfsfunktionen automatisieren.

Die zugrunde liegenden Regeln lauten:

1.) Wenn unterhalb eines Knotens alle Knoten gesetzt sind, ist dieser Knoten gesetzt.

2.) Wenn unterhalb eines Knotens keine Knoten gesetzt ist, ist dieser Knoten nicht gesetzt.

3.) Wenn unterhalb eines Knotens nur einige Knoten gesetzt sind, ist dieser Knoten im Zwischenzustand.

Dazu benötigen wir noch weitere Regeln, die die Aktion festlegen, die beim Klick auf einen Knoten erfolgen soll:

4.) Ein gesetzter Knoten erscheint nach einem Klick als nicht gesetzt; ebenso erscheinen alle in der Hierarchie unter ihm liegenden Knoten als nicht gesetzt.

5.) Ein nicht gesetzter Knoten erscheint nach einem Klick als gesetzt; ebenso erscheinen alle in der Hierarchie unter ihm liegenden Knoten als gesetzt.

Diese letzten beiden Regeln mögen zwar offensichtlich und banal erscheinen. Doch die noch unbeantwortete Frage lautet nun: Was soll passieren, wenn ein Knoten angeklickt wird, der sich im Zwischenzustand befindet? Eine normale, einfache CheckBox im Zwischenzustand erscheint nach einem Klick automatisch als nicht gesetzt. Die noch fehlende Regel könnte also lauten:

6.) Ein im Zwischenzustand befindlicher Knoten erscheint nach einem Klick als nicht gesetzt; ebenso erscheinen alle in der Hierarchie unter ihm liegenden Knoten als nicht gesetzt.

Das Verhalten ausgehend vom Zwischenzustand würde also dem bei einem gesetzten Knoten entsprechen (Regel 4). Aber unbedingt zwingend ist diese Verhaltensweise eigentlich nicht. Denn die Regel könnte auch genau umgekehrt formuliert werden, entsprechend dem Verhalten bei einem zuvor nicht gesetzten Knoten (Regel 5):

6a.) Ein im Zwischenzustand befindlicher Knoten erscheint nach einem Klick als gesetzt; ebenso erscheinen alle in der Hierarchie unter ihm liegenden Knoten als gesetzt.

Ich will Ihnen allerdings nicht vorschreiben, welche der beiden Regelvarianten Sie für Ihre Anwendung vorsehen wollen (auch wenn ich die erste Variante, entsprechend dem Verhalten der Standard-CheckBox, vorziehen würde). Daher ist die folgende Hilfsfunktion, die Sie im Normalfall aus dem NodeClick-Ereignis eines Knotens aufrufen, für beide Fälle ausgelegt.

Sie übergeben der Funktion den angeklickten Knoten im ersten Parameter. Wenn Sie die Funktion im NodeClick-Ereignis aufrufen, soll die Zustandsänderung des Knotens automatisch erfolgen - den zweiten, optionalen Parameter State ignorieren Sie dort. Wenn Sie einen Knoten von einer anderen Stelle in Ihrem Code aus in einen bestimmten Zustand versetzen wollen, können Sie einen der beiden Werte der SemiCheckConstants-Enumeration übergeben (die Werte entsprechen denen der normalen CheckBox - es fehlt allerdings der Wert für den Zwischenzustand, da es keinen Sinn hätte, den Zwischenzustand explizit zu setzen).

Im letzten, ebenfalls optionalen Parameter legen Sie das Verhalten beim Antreffen des Zwischenzustandes fest, indem Sie diesen Parameter weglassen (voreingestellt ist das Standardverhalten), oder einen der beiden Werte der Enumeration SemiCheckModeConstants übergeben.

Public Enum SemiCheckConstants
  scUnchecked
  scChecked
End Enum

Public Enum SemiCheckModeConstants
  scModeClearOnSemi
  scModeCheckOnSemi
End Enum

Public Sub CheckNode(Node As Node, _
 Optional ByVal State As SemiCheckConstants = -1, _
 Optional ByVal Mode As SemiCheckModeConstants = scModeClearOnSemi)

  Select Case State
    Case scUnchecked, scChecked

Wenn Sie keinen zu setzenden Zustand vorgeben, wird hier der aktuelle Zustand des Knotens ausgewertet und der neue Zustand in der hier weiter verwendeten Parameter-Variablen State gesetzt. Der Zustand lässt sich am einfachsten anhand des Namens des aktuell gezeigten Symbols (Image-Eigenschaft des Knotens) ermitteln. Die Namen aller drei Zustandstandssymbole beginnen mit der Zeichenfolge "check", an die der Zustandswert (0, 1 oder 2), den das Symbol repräsentieren soll, als Ziffer angehängt ist.

    Case -1
      Select Case Mode

Beim Standardverhalten entspricht der Zwischenzustand dem gesetzten Zustand:

        Case scModeClearOnSemi
          Select Case Node.Image
            Case "check0"
              State = scChecked
            Case "check1", "check2"
              State = scUnchecked
          End Select

Beim alternativen Verhalten entspricht der Zustand dem nicht gesetzten Zustand:

        Case scModeCheckOnSemi
          Select Case Node.Image
            Case "check0", "check2"
              State = scChecked
            Case "check1"
              State = scUnchecked
          End Select
        Case Else
          Err.Raise 5
      End Select
    Case Else
      Err.Raise 5
  End Select

Zuerst werden alle untergeordneten Knoten auf den neuen Zustand gesetzt (private Hilfsfunktion zCheckNodesDown, siehe unten):

  zCheckNodesDown Node, State

Und anschließend wird der für den aktuellen Knoten neu gesetzte Zustand "nach oben" gereicht:

  zCheckNodesUp Node, State
End Sub

Die Hilfsfunktion, die den neuen Zustand in den untergeordneten Knoten setzt, ist trivial. Sie ruft sich selbst rekursiv auf, so lange ein Knoten noch weitere Kind-Knoten hat, und setzt den neuen Zustand im jeweiligen Knoten.

Private Sub zCheckNodesDown(Node As Node, ByVal State As SemiCheckConstants)
  Dim nChildNode As Node
  
  With Node
    Set nChildNode = .Child
    .Image = "check" & CStr(State)
    Do While Not (nChildNode Is Nothing)
      zCheckNodesDown nChildNode, State
      Set nChildNode = nChildNode.Next
    Loop
  End With
End Sub

Um einiges komplizierter ist das Anpassen der übergeordneten Knoten in der privaten Hilfsfunktion zCheckNodesUp, deren Zustände ja nicht nur vom Zustand des aktuell gesetzten Knotens abhängen, sondern auch von der "Aufsummierung" der Zustände aller Knoten auf jeweils einer Ebene. Auch diese Hilfsfunktion ruft sich selbst rekursiv so lange immer wieder auf, bis die oberste Ebene erreicht worden ist (d.h. bis kein Eltern-Knoten mehr vorhanden ist, die Parent-Eigenschaft eines Knotens also Nothing zurückgibt). Da wir es in dieser Aufrufkette mit allen drei Zuständen zu tun haben können, wird hier der zweite Parameter der Funktion, State, als Typ der VB-eigenen Enumeration CheckBoxConstants deklariert.

Private Sub zCheckNodesUp(Node As Node, ByVal State As CheckBoxConstants)
  Dim nSibling As Node
  Dim nParentNode As Node
  Dim nCheckCount As Long
  Dim nSiblingsCount As Long
  Dim nSemi As Boolean
  
  With Node

Zunächst wird der gerade übergebene Knoten auf den übergebenen Zustand gesetzt. Beim ersten Aufruf ist der Zustand zwar bereits gesetzt, aber es schadet nichts, ihn erneut zu setzen.

    .Image = "check" & CStr(State)
    Set nParentNode = .Parent
    If Not (nParentNode Is Nothing) Then

Wenn noch ein Elternknoten vorhanden ist, prüfen wir, welcher Zustand für diesen Aufruf der Funktion übergeben worden ist. Vor allem beim ersten Aufruf kann es sich nur um einen der beiden "eindeutigen" Zustände handeln:

      Select Case State
        Case vbChecked, vbUnchecked

Wir holen den ersten Schwester-Knoten des gerade übergebenen Knotens:

          Set nSibling = .FirstSibling
          Do While Not (nSibling Is Nothing)

Falls vorhanden, zählen wir die Schwesterknoten durch:

            nSiblingsCount = nSiblingsCount + 1

Dann betrachten wir den Zustand des jeweiligen Schwesterknotens

            Select Case nSibling.Image
              Case "check0"

Ist der Zustand gesetzt, wird der Zustand der aktuellen Geschwister-Ebene mindestens der Zwischenzustand werden:

              Case "check1"
                nSemi = True

Die gesetzten Knoten dieser Ebene zählen wir separate ebenfalls durch:

                nCheckCount = nCheckCount + 1

Ist der Zustand bereits ein Zwischenzustand, wird der Zustand der Geschwister-Ebene ebenfalls mindestens mindestens ein Zwischenzustand werden:

              Case "check2"
                nSemi = True
            End Select
            Set nSibling = nSibling.Next
          Loop

Ist die Anzahl aller Geschwister-Knoten gleich der Anzahl der gesetzten Knoten, gilt der Zustand der ganzen Ebene als "gesetzt":

          If nSiblingsCount = nCheckCount Then
            State = vbChecked

Ist die Anzahl ungleich, und war mindestens in Knoten der Ebene gesetzt oder im Zwischenzustand, ist die ganze Ebene im Zwischenzustand:

          ElseIf nSemi Then
            State = vbGrayed

Im verbleibenden Fall war kein Knoten der Ebene gesetzt oder im Zwischenzustand, so dass die ganze Ebene den Zustand "nicht gesetzt" erhält:

          Else
            State = vbUnchecked
          End If

Wurde bereits der Zwischenzustand übergeben, ändert sich nichts - er wird einfach weitergegeben:

        Case vbGrayed
      End Select

Hier wird nun der ermittelte Zustand der Ebene an den Eltern-Knoten weitergegeben, der zu Beginn des nun folgenden Aufrufs bei diesem gesetzt wird:

      zCheckNodesUp nParentNode, State
    End If
  End With
End Sub

Beispiel-Projekt und Modul modTvwSemiChecks (tvwsemichecks.zip - ca. 5,1 KB)


Artikel
Zum Download-Bereich dieses Artikel
Mail an den Autor dieses Artikels

KnowHow
Zur KnowHow-Übersicht

KnowHow-Themen
Themen - Allgemeines
Themen - Entwicklungsumgebung (VB-IDE)
Themen - Forms
Themen - Steuerelemente (Controls)
Themen - Grafik
Themen - Dateien
Themen - UserControls
Themen - Einsteiger-Tipps
Themen - Wussten Sie...?

Übersicht nach Titeln in alphabetischer Reihenfolge
Übersicht nach Erscheinungsdatum

Schnellsuche




Zum Seitenanfang

Copyright © 1999 - 2017 Harald M. Genauck, ip-pro gmbh  /  Impressum

Zum Seitenanfang

Zurück...

Zurück...

Download Internet Explorer