Die Flex Tree Komponente für Kategorien mit Drag & Drop – Teil 1

von Thomas Müller

Die Tree Komponente ist sehr hilfreich um hierarchische Daten darzustellen. Angedacht ist die Komponente, wie der Name vermuten lässt, als Baum mit Knoten und Blättern. So wird er auch in den Beispielen auf der Adobe Seite dargestellt. Entwickelt man eine Flex Anwendung, kommt man oft an einen Punkt, an dem Daten kategorisiert werden müssen. Was eignet sich dazu besser als die Tree Komponente? Wie sich heraus stellt, ist sie jedoch nicht 100%ig für einen derartigen Einsatz geschaffen.

Die erste, kosmetische Änderung die an einem Tree zur Darstellung von Verschachtelten Kategorien vorgenommen werden muss, ist die Darstellung der Blätter. Alle Elemente in dem Tree sollen Kategorien darstellen.

[Bindable]
 [Embed("images/icons/folder.png")]
 protected var MyFolderIcon:Class;
 
[Bindable]
 [Embed("images/icons/folder-open.png")]
 protected var MyFolderOpenIcon:Class;
 
<mx:Tree id="tree" defaultLeafIcon="{MyFolderIcon}"
 folderOpenIcon="{MyFolderOpenIcon}"
 folderClosedIcon="{MyFolderIcon}">

Durch den Einsatz von eigenen Grafiken für Blätter und Knoten wurde ein einheitliches Aussehen geschaffen. In der von mir entwickelten Anwendung löst ein Klick auf ein Element des Trees ein Event aus, das dazu führt das ein Datagrid alle Objekte die zu der ausgewählten Kategorie gehören, anzeigt.

Der Tree bietet die Möglichkeit, dass Elemente mittels Drag & Drop neu zu arrangieren. Dazu müssen lediglich einige Eigenschaften des Trees gesetzt werden.

<mx:Tree id="tree" defaultLeafIcon="{MyFolderIcon}"
 folderOpenIcon="{MyFolderOpenIcon}"
 folderClosedIcon="{MyFolderIcon}"
dragMoveEnabled="true" dragEnabled="true" dropEnabled="true">

Und schon kann der Tree beliebig sortiert werden. Ein Beispiel dazu liefert Adobe. Doch kann wirklich beliebig sortiert werden? Nein! Warum? Es ist nicht möglich ein Element “in” ein anderes herein zu schieben. Was bedeutet das für die Darstellung von Kategorien? Es ist nicht möglich eine Kategorie in eine andere Kategorie, die keine Kinder hat, zu verschieben. Dies fällt nicht nur mir auf, auch bei FlexExamples wurde dieses Verhalten bemängelt:

Rob McKeown November 30, 2007 at 2:12 pm

One thing to note about the tree is that it is really just a list in which items are displayed. What that means is, you can’t really drop somthing “into” folder unless the folder is open. Even in that case the user experience isn’t quite right. So try moving everything out of one of the folders and then collapse that empty folder. If you drop something “on” the folder, it actually winds up between the target folder and the one below or above. This is indicated by the black line showing up as you move the mouse over the folders. If you “open” the folder (the only way to tell it is open is by the arrow) and then try it, you end up with an additional drop zone that is basically the bottom half of the opened, empty folder. This is also indicated by the black lines position.

It would be better if the middle section of any item could always be the drop zone for “add to this folder” and the top and bottom edges could be for dropping above or below respectively.

Besser kann ich das Verhalten des Trees nicht beschreiben. Leider habe ich dieses Verhalten erst festgestellt, als ich das Verschieben der Kategorien bereits in Flex und im Webservice implementiert habe. Alles funktioniert, jedoch war es nicht möglich, eine Kategorie in eine andere ohne Kinder zu verschieben. So konnte es nicht bleiben, eine Workaround wurde benötigt.

Nach einigem Probieren kam ich zu dem Entschluss, dass es am einfachsten zu realisieren ist, indem einer Kategorie ein Kind hinzugefügt wird, wenn sie keiner Kinder besitzt. Der Ablauf sieht wie folgt aus:

  • Der Benutzer zieht eine Kategorie
  • Jedes mal, wenn der Benutzer die gezogene Kategorie über eine andere Kategorie zieht, wird ein Timer gestartet um zu messen, wie lange er über der Kategorie verweilt
  • Ist eine bestimmte Zeit (in meiner Anwendung 2 Sekunden) erreicht und hat die Kategorie über der der Benutzer verweilt, wird der Kategorie ein Kind mit dem Titel “Als Unterkategorie einfügen” hinzugefügt
  • Bewegt der Benutzer die gezogene Kategorie weiter, wird das neu hinzugefügte Kind wieder entfernt
  • Nach erfolgtem Verschieben wird das Kind ebenfalls entfernt

Durch diese Technik ist es möglich geworden, dass Kategorien auch in andere, die keine Kinder haben, zu verschieben. In meinem nächsten Posting werde ich mich der Implementierung widmen. Dabei werden neben der, in diesem Posting beschriebenen, Problematik auch weitere Probleme behandelt. Wie verhindere ich, dass eine Kategorie in eine eigene Unterkategorie – und damit in sich selber, verschoben wird? Wie lese ich aus, wohin die Kategorie verschoben wurde, wenn die Datenquelle des Trees kein XML ist? Wie setze ich das Verschieben auf Seiten des Webservices um?