Aufgaben per TreeView verwalten

Aufgaben lassen sich normalerweise schön in einer Liste darstellen. Manche Aufgaben sind aber derart umfangreich, dass man sie lieber in kleine Häppchen aufteilt und diese nacheinander erledigt. Also stellen wir dies in hierarchischer Form im TreeView dar. Zusammen mit der Möglichkeit, Aufgaben per Kontextmenü anzulegen und zu löschen, Unteraufgaben zu verschieben oder erledigte Aufgaben abzuhaken, wird eine richtige kleine Lösung daraus. Es kommt aber noch besser: Das Ergebnis dieses Beitrags verwenden wir in unserer Lösung “Tagesablauf verwalten” weiter.

Die Lösung im Überblick

Die Aufgabenverwaltung soll das Anlegen, Bearbeiten, Löschen und Zuordnen von Aufgaben erleichtern. Die Aufgaben liegen in einer Tabelle, eine weitere erlaubt die hierarchische Zuordnung der Aufgaben. Hierarchie Natürlich: Hier kommt das TreeView-Steuerelement zum Einsatz. Es zeigt die Aufgaben wie in Bild 1 an.

pic006.png

Bild 1: Anzeige von Aufgaben per TreeView-Steuerelement

In der Abbildung erkennen Sie auch bereits, wie Sie Aufgaben anlegen und löschen: nämlich per Kontextmenüeintrag. Der Eintrag Neue Aufgabe öffnet den Dialog aus Bild 2, mit dem Sie eine neue Aufgabe anlegen können. Dort tragen Sie Informationen wie den Namen der Aufgabe, eine Beschreibung, das geplante und das tatsächliche Erledigungsdatum ein, wählen eine Kategorie aus und stellen ein, ob die Aufgabe heute erledigt werden soll. Ein Klick auf OK schließt das Formular und fügt die neue Aufgabe gleich zum Baum hinzu – und zwar unterhalb des Elements, dessen Kontextmenü Sie zuvor benutzt haben.

pic007.png

Bild 2: Anlegen einer neuen Aufgabe

Die Lösung bietet noch mehr: So können Sie eine Aufgabe per Doppelklick in der Detailansicht öffnen, um nachträgliche änderungen vorzunehmen. änderungen an der Bezeichnung werden gleich in das TreeView-Steuerelement übernommen.

Nicht sichtbar, aber sehr nützlich ist die Möglichkeit, Aufgaben per Drag and Drop zu verschieben oder zu kopieren. Das Verschieben erledigen Sie, indem Sie ein Element bei gedrückter Maustaste auf ein anderes Element ziehen. Die Aufgabe wird der Zielaufgabe untergeordnet.

Wenn Sie beim Drag-and-Drop-Vorgang die Strg-Taste gedrückt halten, legt die Anwendung eine Kopie der betroffenen Aufgabe an und speichert diese direkt unterhalb der Zielaufgabe. Die Aufgabe erhält dann genau die gleichen Eigenschaften wie die Originalaufgabe.

Sollten Sie eine Aufgabe ein zweites Mal unterhalb einer Aufgabe anlegen wollen, ziehen Sie diese einfach bei gedrückter Strg-Taste auf die gemeinsame übergeordnete Aufgabe.

Der Aufgabenbaum soll eine Übersicht über alle zu erledigenden Aufgaben bieten. In der Lösung Tagesablauf verwalten, die wir im nächsten Heft vervollständigen, wird der Aufgabenbaum neben einer Liste der heute zu erledigenden Aufgaben und einem Zeitplan für den jeweiligen Tag dargestellt. Sie können dann Aufgaben aus dem Aufgabenbaum per Drag and Drop in die verschiedenen Listen ziehen – entweder als Aufgabe in die Liste der heutigen Aufgaben oder auch als Tätigkeit in die Liste der Tätigkeiten des entsprechenden Tages.

Die Aufgabendetails enthalten eine Eigenschaft, mit der Sie eine Kategorie festlegen können. Diese wählen Sie entweder per Kombinationsfeld aus den bestehenden Kategorien aus oder Sie klicken auf die Schaltfläche mit den drei Punkten. Dies öffnet zunächst den Dialog Kategorie-Übersicht aus Bild 3. Hier können Sie eine der vorhandenen Kategorien auswählen, Kategorien löschen oder neue Kategorien anlegen. In jedem Fall wird hier gleich die bereits gewählte Kategorie ausgewählt und beim Schließen des Formulars übernommen.

pic008.png

Bild 3: Auswählen und verwalten der Kategorien

Datenmodell

Die Grundlage für unseren Aufgabenbaum ist eine Tabelle namens tblAufgaben, welche die wesentlichen Informationen über eine Aufgabe enthält: Die Bezeichnung, eine Kurzbeschreibung, Felder zum Eintragen von Datumsangaben wie dem geplanten und dem tatsächlichen Erledigungsdatum sowie ein Auswahlfeld für eine Kategorie. Schließlich besitzt die Tabelle noch ein Ja/Nein-Feld namens HeuteErledigen. Warum das, wenn es doch bereits ein Fertigstellungsdatum gibt Nun: Auch wenn eine Aufgabe erst in einer Woche fertiggestellt werden muss, kann man sie ja durchaus schon vorher erledigen. Und da für die Tagesablauf-Verwaltung, zu der die hier vorgestellte Teillösung gehören soll, auch eine Liste der für den heutigen Tag vorgesehenen Aufgaben geplant ist, wollen wir solche Aufgaben mit dem Wert True für die Eigenschaft HeuteErledigen kennzeichnen. Die Tabelle sieht im Entwurf wie in Bild 4 aus.

pic001.png

Bild 4: Entwurf der Tabelle tblAufgaben

Außerdem benötigen wir noch eine Möglichkeit, die hierarchische Abhängigkeit einzelner Aufgaben voneinander abzubilden. Dazu verwenden wir eine weitere Tabelle namens tblAufgabenUnteraufgaben, die neben einem Primärschlüsselfeld zwei Fremdschlüsselfelder namens AufgabeID und UnteraufgabeID besitzt. Für das Feld UnteraufgabeID wird ein eindeutiger Index festgelegt, damit eine Unteraufgabe nicht gleichzeitig mehreren Aufgaben zugeordnet werden kann (s. Bild 5).

pic002.png

Bild 5: Entwurf der Tabelle tblAufgabenUnteraufgaben

Die Beziehung zwischen den Tabellen tblAufgaben und tblAufgabenUnteraufgaben legen Sie gleich im Beziehungen-Fenster fest. Da die Tabelle tblAufgaben zweimal mit der Tabelle tblAufgabenUnteraufgaben verknüpft ist, blenden Sie diese zum Herstellen der Verknüpfungen ein zweites Mal im Beziehungen-Fenster ein. Die Beziehung zwischen dem Feld AufgabeID der Tabelle tblAufgabenUnteraufgaben und der Tabelle tblAufgaben erhalten Sie, indem Sie das Feld von tblAufgaben auf das gleichnamige Feld der Tabelle tblAufgabenUnteraufgaben ziehen. Dies könnten Sie in diesem Fall auch andersherum erledigen, aber nicht bei der Verknüpfung mit dem Feld UnteraufgabeID: Dieses Feld ist mit einem eindeutigen Index versehen. Wenn Sie es von tblAufgabenUnteraufgaben auf das Feld AufgabeID der Tabelle tblAufgaben ziehen, fungiert das Feld AufgabeID der Tabelle tblAufgaben als Fremdschlüsselfeld. Bei gleichzeitiger Definition referentieller Integrität für diese Beziehung bedeutet dies, dass Sie nur Datensätze in tblAufgaben anlegen können, deren Feld AufgabeID einen Wert enthält, der bereits im Feld UnteraufgabeID der Tabelle tblAufgabenUnteraufgaben enthalten ist. Anderenfalls erhalten Sie beim Einfügen eines Datensatzes in der Tabelle tblAufgaben die Fehlermeldung Der Datensatz kann nicht hinzugefügt oder geändert werden, da ein Datensatz in der Tabelle €štblAufgabenUnteraufgaben€ mit diesem Datensatz in Beziehung stehen muss. Wenn Sie hingegen das Feld AufgabeID von der Tabelle tblAufgaben auf das Feld UnteraufgabeID der Tabelle tblAufgabenUnteraufgaben ziehen, funktioniert alles wie gewünscht – Sie können dann einfach Datensätze in der Tabelle tblAufgaben anlegen, ohne dass die Tabelle tblAufgabenUnteraufgaben davon betroffen ist. Dass das Feld UnteraufgabeID mit einem eindeutigen Index versehen ist, sorgt außerdem dafür, dass die Beziehung als 1:1-Beziehung gekennzeichnet wird (s. Bild 6).

pic003.png

Bild 6: Datenmodell der Aufgabenverwaltung

Aufbau der Lösung

Die Aufgabenverwaltung per TreeView soll hauptsächlich das Hinzufügen und Löschen von Aufgaben über das Kontextmenü des TreeView-Steuerelements ermöglichen. Wie soll jedoch sichergestellt werden, dass überhaupt ein Element im TreeView-Steuerelement vorhanden ist, das ein Kontextmenü anbietet Man könnte nun alle Rootaufgaben, also solche Aufgaben, die keine übergeordneten Aufgaben besitzen, in der ersten Ebene des TreeViews anzeigen. Allerdings fehlt dann immer noch ein Element, mit dessen Kontextmenü Sie ein Rootelement anlegen können. Der Einfachheit halber legen wir daher im TreeView ein einziges Root-Element an, das alle weiteren Rootaufgaben und auch einen Kontextmenüeintrag zum Anlegen von Rootaufgaben enthält. Auf diese Weise können Sie auch eine leere Datenbank mit diesem Formular weitergeben und dem Benutzer so die Möglichkeit geben, seine Aufgaben-Hierarchie von Grund auf neu zu gestalten.

ähnliches gilt für die Kategorien, die der Benutzer für die Aufgaben auswählen soll. Was geschieht, wenn der Benutzer das Aufgaben-Detailformular öffnet, um eine neue Aufgabe anzulegen, aber noch keine Kategorien vorhanden sind Grundsätzlich sollte bereits vor dem Öffnen dieses Dialoges eine entsprechende Meldung erscheinen und den Benutzer auffordern, zunächst mindestens eine Kategorie anzulegen.

Alternativ richten Sie das Kategorien-Auswahlsteuerelement im Aufgaben-Detailformular so ein, dass es die direkte Eingabe von Kategorien erlaubt und diese gleich als neue Datensätze der Tabelle tblKategorien speichert. Rechts neben dem Kombinationsfeld ließe sich dann gut eine Schaltfläche unterbringen, mit welcher der Benutzer den Dialog zum Verwalten der Kategorien öffnen kann.

TreeView-Steuerelement anlegen

Das TreeView-Steuerelement fügen Sie über den Eintrag ActiveX-Steuerelemente der Toolbox mit den Steuerelementen zu einem neuen, leeren Formular hinzu. Ziehen Sie das Steuerelement auf die gewünschte Größe und nennen Sie es ctlTreeView.

Das TreeView-Steuerelement soll per VBA-Code mit den reflexiven Daten der beiden Tabellen tblAufgaben und tblAufgabenUnteraufgaben beziehungsweise mit den darauf aufbauenden Tabellen gefüllt werden. Außerdem wollen wir später einige Features wie beispielsweise Kontextmenüeinträge zum Anlegen und Entfernen der Aufgaben im TreeView hinzufügen.

Damit diese Kontextmenüs angezeigt werden, müssen beim Rechtsklick auf die entsprechenden Elemente Ereignisse ausgelöst werden. Damit wir diese zum Klassenmodul des Formulars hinzufügen können, deklarieren wir im Kopf des Moduls die folgende Objektvariable:

Dim WithEvents objTreeView As MSComctlLib.TreeView

Das Schlüsselwort WithEvents sorgt für die Bereitstellung der Ereignisprozeduren über die beiden Kombinationsfelder im VBA-Fenster mit dem Klassenmodul des Formulars.

Bevor wir uns um diese Ereignisse kümmern, wollen wir die Objektvariable zunächst mit einem Verweis auf das TreeView-Steuerelement ctlTreeView füllen und dann die Aufgaben darin anzeigen.

TreeView mit Aufgaben füllen

Das TreeView-Steuerelement soll ein Root-Steuerelement namens a0 mit der Beschriftung Aufgaben haben. Dieses Element legen Sie gleich beim Einrichten des TreeView-Steuerelements in der Ereignisprozedur an, die durch das Ereignis Beim Laden des Formulars ausgelöst wird.

Diese Prozedur füllt zunächst die Objektvariable objTreeView mit einem Verweis auf das TreeView-Steuerelement (s. Listing 1). Danach nimmt es einige Einstellungen vor, die Sie auch direkt im Eigenschaftsfenster des TreeView-Steuerelements im Formularentwurf vornehmen können. Wenn Sie jedoch öfter mal TreeView-Steuerelemente anlegen, möchten Sie vielleicht auf die Schnelle die Eigenschaften bewährter Modelle übernehmen – und das geht am schnellsten, wenn Sie einfach ein paar Zeilen Code übertragen, in diesem Fall die Anweisungen mit der Zuweisung der entsprechenden Eigenschaftswerte.

Listing 1: Einrichten des TreeView-Steuerelements beim Laden des Formulars

Private Sub Form_Load()
    Dim objNode As MSComctlLib.Node
    Set objTreeView = Me!ctlTreeView.Object
    With objTreeView
        .Appearance = ccFlat
        .LineStyle = tvwTreeLines
        .Style = tvwTreelinesPlusMinusPictureText
        .OLEDragMode = ccOLEDragAutomatic
        .OLEDropMode = ccOLEDropManual
        .Font.Name = "Calibri"
        .Font.Size = 10
        Set objNode = .Nodes.Add(, , "a0", "Aufgaben")
        objNode.Expanded = True
        FillTree
    End With
End Sub

Der Root-Knoten mit der Beschriftung Aufgaben und dem Key a0 wird nach dem Einstellen der Eigenschaften zum TreeView-Steuerelement hinzugefügt. Außerdem wird dessen Eigenschaft Expanded gleich auf den Wert True eingestellt, damit darunter enthaltene Aufgaben gleich angezeigt werden.

Einlesen der ersten Aufgaben-Ebene

Die letzte Anweisung der Prozedur Form_Load ruft eine weitere Prozedur namens FillTree auf. Diese füllt genau genommen gar nicht den kompletten Baum, sondern kümmert sich nur um die erste Ebene. Woher aber wissen wir, welche der Aufgaben aus der Tabelle tblAufgaben dort landen sollen, wo doch die Informationen über die Hierarchie in der Tabelle tblAufgabenUnteraufgaben gespeichert sind Dort sollen aber doch gerade über die Aufgaben ohne übergeordnete Elemente keine Informationen enthalten sein, sondern andersherum Kein Problem: Wir verknüpfen die beiden Tabellen trotzdem einfach in einer Abfrage, und zwar über das Feld UnteraufgabeID der Tabelle tblAufgabenUnteraufgaben.

Außerdem legen wir in den Beziehungseigenschaften für diese Beziehung fest, dass die Beziehung alle Datensätze der Tabelle tblAufgaben liefern soll, aber nur diejenigen Datensätze der Tabelle tblAufgabenUnteraufgaben, für die auch ein verknüpfter Datensatz vorhanden ist. Dies liefert dann manche Datensätze der Tabelle tblAufgaben mit einem verknüpfen Datensatz der Tabelle tblAufgabenUnteraufgaben und manche ohne weitere Daten aus tblAufgabenUnteraufgaben. Letztere sind diejenigen, die wir suchen: Und mit einem Kriterium, das alle Datensätze liefert, für die das Feld AufgabeID der Tabelle tblAufgabenUnteraufgaben den Wert NULL hat, erhalten wir schließlich alle Aufgaben ohne übergeordnete Aufgaben. Die Abfrage sieht im Entwurf wie in Bild 7 aus.

pic005.png

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar