Ein eigenes TreeModel schreiben: Unterschied zwischen den Versionen
K (→Das Interface TreeModel) |
K (→Dynamisches TreeModel implementieren) |
||
(15 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
Zeile 5: | Zeile 5: | ||
Damit der JTree das darzustellende Datenformat verstehen kann, muss dieses einem entsprechenden Standard genügen. Den kleinsten gemeinsamen Nenner bildet hier das {{JAPI|TreeModel}}. | Damit der JTree das darzustellende Datenformat verstehen kann, muss dieses einem entsprechenden Standard genügen. Den kleinsten gemeinsamen Nenner bildet hier das {{JAPI|TreeModel}}. | ||
− | Im Gegensatz zu {{JAPI|JTable}} existiert für den JTree keine abstrakte Standardimplementierung seines Datenmodells. JTable bietet hier die [[Klasse]] {{JAPI|AbstractTableModel}} welche das [[Interface]] {{JAPI|TableModel}} implementiert an. Diese Klasse enthält bereits eine einfache Verarbeitung von {{JAPI|TableModelEvent}}s, reagiert also auf Veränderungen im TableModel. AbstractTableModel wird schließlich von {{JAPI|DefaultTableModel}} beerbt, mit dem Tabellen mit Standard-Datentypen wie bspw. {{JAPI|Integer}}, {{JAPI|Double}}, {{JAPI|Float}}, {{JAPI|Boolean}}, {{JAPI|String}}, {{JAPI|Icon}} erzeugt werden können. | + | Im Gegensatz zu {{JAPI|JTable}} existiert für den JTree keine abstrakte Standardimplementierung seines Datenmodells. JTable bietet hier die [[Klasse]] {{JAPI|AbstractTableModel}} welche das [[Interface]] {{JAPI|TableModel}} implementiert an. Diese Klasse enthält bereits eine einfache Verarbeitung von {{JAPI|TableModelEvent}}s, reagiert also auf Veränderungen im TableModel. AbstractTableModel wird schließlich von {{JAPI|DefaultTableModel}} beerbt, mit dem Tabellen mit Standard-Datentypen wie bspw. {{JAPI|Integer}}, {{JAPI|Double}}, {{JAPI|Float}}, {{JAPI|Boolean}}, {{JAPI|String}}, {{JAPI|Icon}} erzeugt werden können. |
− | Eine vergleichbare Klasse ''AbstractTreeModel'' gibt es in der Java-API nicht. Für eigene baumartig strukturierte Datentypen muss hier ein eigenes TreeModel geschrieben werden. Mit {{JAPI|DefaultTreeModel}} gibt es schon eine Standardimplementierung eines TreeModels. Die Daten des Baums werden mit Hilfe von Objekten, die das Interface {{JAPI|TreeNode}} implementieren, dargestellt. Veränderbare Daten erfordern den Einsatz von {{JAPI|MutableTreeNode}}. Eine Standardimplementierung wird bereits mit {{JAPI|DefaultMutableTreeNode}} von der Java-API mitgeliefert. '''Mehr dazu im großen [[JTree (Tutorial)©]].''' | + | '''Mehr zu all dem im großen [[JTable (Tutorial)©]].''' |
+ | |||
+ | Eine vergleichbare Klasse ''AbstractTreeModel'' gibt es in der Java-API nicht. Für eigene baumartig strukturierte Datentypen muss hier ein eigenes TreeModel geschrieben werden. Mit {{JAPI|DefaultTreeModel}} gibt es schon eine Standardimplementierung eines TreeModels. Die Daten des Baums werden mit Hilfe von Objekten, die das Interface {{JAPI|TreeNode}} implementieren, dargestellt. Veränderbare Daten erfordern den Einsatz von {{JAPI|MutableTreeNode}}. Eine Standardimplementierung wird bereits mit {{JAPI|DefaultMutableTreeNode}} von der Java-API mitgeliefert. | ||
+ | |||
+ | '''Mehr dazu im großen [[JTree (Tutorial)©]].''' | ||
==Das Interface TreeModel== | ==Das Interface TreeModel== | ||
Zeile 31: | Zeile 35: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | ==TreeModel implementieren== | + | ==Dynamisches TreeModel implementieren== |
+ | Im Folgenden werden wir schrittweise ein dynamisches TreeModel implementieren. | ||
+ | |||
+ | Nehmen wir an, wir hätten bereits eine eigene Datenstruktur, die die Produktion von Fahrrädern speichert und die wir im JTree präsentieren und zur Laufzeit auch verändern wollen. | ||
+ | |||
+ | Um ein eigenes TreeModel zu implementieren, müssen wir nun also erstmal das {{JAPI|TreeModel}}-[[Interface]] implementieren und damit alle von ihm vorgeschriebenen Methoden überschreiben: | ||
+ | |||
+ | <syntaxhighlight lang="java"> | ||
+ | public BicycleTreeModel implements TreeModel { | ||
+ | |||
+ | @Override | ||
+ | public Object getChild(Object parent, int index) { | ||
+ | |||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public int getChildCount(Object parent) { | ||
+ | |||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public int getIndexOfChild(Object parent, Object child) { | ||
+ | |||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public Object getRoot() { | ||
+ | |||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public boolean isLeaf(Object node) { | ||
+ | |||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void addTreeModelListener(TreeModelListener l) { | ||
+ | |||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void removeTreeModelListener(TreeModelListener l) { | ||
+ | |||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void valueForPathChanged(TreePath path, Object newValue) { | ||
+ | |||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ===TreeModelListener verwalten=== | ||
+ | Komponenten wie der JTree interessieren sich für das Geschehen in einem TreeModel und lauschen auf Ereignisse, die sich durch Benutzeraktionen ergeben. Das kann z. B. das Hinzufügen, Ändern oder Löschen von Datenelementen im TreeModel sein. | ||
+ | |||
+ | Damit ein Ereignis-Interessent ({{JAPI|TreeModelListener}}) die Benachrichtigungen über {{JAPI|TreeModelEvent}}s abonieren kann, muss er sich als Abonent registrieren. | ||
+ | |||
+ | Mit der [[Klasse]] {{JAPI|EventListenerList}} gibt es in Java bereits eine fertige Ereignis-Lauscher-Liste, die für alle möglichen [...]ModelListener-Typen eingesetzt werden kann.<br> | ||
+ | Im Folgenden kümmern wir uns also darum, dass wir diese EventListenerList in unser TreeModel einbauen und auch die Möglichkeit schaffen, dass sich Interessenten für die Benachrichtigung über TreeModelEvents an unserem "Abo-Dienst" anmelden und auch von ihm wieder abmelden können. | ||
+ | |||
+ | Zeit, um den bereits implementierten Methoden <code>addTreeModelListener(TreeModelListener l)</code> und <code>removeTreeModelListener(TreeModelListener l)</code> etwas Code zu geben! | ||
+ | <syntaxhighlight lang="java"> | ||
+ | public BicycleTreeModel implements TreeModel { | ||
+ | |||
+ | private final EventListenerList listeners; | ||
+ | |||
+ | [...] | ||
+ | |||
+ | @Override | ||
+ | public void addTreeModelListener(TreeModelListener l) { | ||
+ | listeners.remove(TreeModelListener.class, listener); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void removeTreeModelListener(TreeModelListener l) { | ||
+ | listeners.add(TreeModelListener.class, listener); | ||
+ | } | ||
+ | |||
+ | [...] | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ===Ein Konstruktor für unser TreeModel=== | ||
+ | Wie wir oben bereits angenommen haben, haben wir vielleicht schon eine Datenstruktur, die die Produktion von Fahrrädern verwaltet und speichert. Dann sollte unser [[Konstruktor]] per Parameter diese Datenstruktur auch übernehmen, um sie dann in unserem TreeModel weiter auslesen, und beschreiben zu können. Vorteil hier; ohne unsere Datenstruktur anpassen zu müssen, können wir diese nun auch über den JTree verwalten und vor allem darstellen. | ||
+ | |||
+ | <syntaxhighlight lang="java"> | ||
+ | public BicycleTreeModel implements TreeModel { | ||
+ | |||
+ | private final EventListenerList listeners; | ||
+ | private final BicycleProduction production; | ||
+ | |||
+ | public BicycleTreeModel(BicycleProduction production) { | ||
+ | listeners = new EventListenerList(); | ||
+ | this.production = production; | ||
+ | } | ||
+ | |||
+ | [...] | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ===getRoot()-Methode implementieren=== | ||
+ | Weiter geht es mit der Implementierung der TreeModel-Methoden. Schrittweise werden wir nun die Methoden mit sinnvollem Code füllen. | ||
+ | |||
+ | Die getRoot()-Methode soll den Wurzelknoten des Baumes zurückgeben. Die Verknüpfung von Elementen aus unserer bestehenden Datenstruktur mit einem Baumknoten kann recht einfach wie komfortabel über die von der [[API]] bereitgestellten Klasse {{JAPI|DefaultMutableTreeNode}} erledigt werden. '''Mehr dazu im großen [[JTree (Tutorial)©]]'''. | ||
+ | |||
+ | <syntaxhighlight lang="java"> | ||
+ | public BicycleTreeModel implements TreeModel { | ||
+ | |||
+ | private final EventListenerList listeners; | ||
+ | private final BicycleProduction production; | ||
+ | private final DefaultMutableTreeNode root; | ||
+ | |||
+ | public BicycleTreeModel(BicycleProduction production) { | ||
+ | listeners = new EventListenerList(); | ||
+ | this.production = production; | ||
+ | root = new DefaultMutableTreeNode(production.getPeriod()); | ||
+ | for (Bicycle bicycle : production.getBicycleList()) { | ||
+ | root.add(new DefaultMutableTreeNode(bicycle)); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * @see javax.swing.tree.TreeModel#getRoot() | ||
+ | */ | ||
+ | @Override | ||
+ | public Object getRoot() { | ||
+ | return root; | ||
+ | } | ||
+ | |||
+ | [...] | ||
+ | } | ||
+ | </syntaxhighlight> | ||
{{In Arbeit}} | {{In Arbeit}} |
Aktuelle Version vom 3. Februar 2022, 11:44 Uhr
TreeModels enthalten die Daten, die ein JTree
darstellen soll. In diesem Artikel werden wir uns damit befassen, wie man Schritt für Schritt ein eigenes dynamisches TreeModel
aufbaut. Nach der Lektüre dieses Artikels sollte der Leser in der Lage sein, selbstständig eigene TreeModels zu entwickeln.
Inhaltsverzeichnis
Überblick
Damit der JTree das darzustellende Datenformat verstehen kann, muss dieses einem entsprechenden Standard genügen. Den kleinsten gemeinsamen Nenner bildet hier das TreeModel
.
Im Gegensatz zu JTable
existiert für den JTree keine abstrakte Standardimplementierung seines Datenmodells. JTable bietet hier die Klasse AbstractTableModel
welche das Interface TableModel
implementiert an. Diese Klasse enthält bereits eine einfache Verarbeitung von TableModelEvent
s, reagiert also auf Veränderungen im TableModel. AbstractTableModel wird schließlich von DefaultTableModel
beerbt, mit dem Tabellen mit Standard-Datentypen wie bspw. Integer
, Double
, Float
, Boolean
, String
, Icon
erzeugt werden können.
Mehr zu all dem im großen JTable (Tutorial)©.
Eine vergleichbare Klasse AbstractTreeModel gibt es in der Java-API nicht. Für eigene baumartig strukturierte Datentypen muss hier ein eigenes TreeModel geschrieben werden. Mit DefaultTreeModel
gibt es schon eine Standardimplementierung eines TreeModels. Die Daten des Baums werden mit Hilfe von Objekten, die das Interface TreeNode
implementieren, dargestellt. Veränderbare Daten erfordern den Einsatz von MutableTreeNode
. Eine Standardimplementierung wird bereits mit DefaultMutableTreeNode
von der Java-API mitgeliefert.
Mehr dazu im großen JTree (Tutorial)©.
Das Interface TreeModel
Das Interface TreeModel
schreibt Methoden vor, die eine Klasse implementieren muss, wenn ein JTree
die in ihr enthaltenen Daten grafisch darstellen können soll.
public interface TreeModel {
void addTreeModelListener(TreeModelListener l);
Object getChild(Object parent, int index);
int getChildCount(Object parent);
int getIndexOfChild(Object parent, Object child);
Object getRoot();
boolean isLeaf(Object node);
void removeTreeModelListener(TreeModelListener l);
void valueForPathChanged(TreePath path, Object newValue);
}
Dynamisches TreeModel implementieren
Im Folgenden werden wir schrittweise ein dynamisches TreeModel implementieren.
Nehmen wir an, wir hätten bereits eine eigene Datenstruktur, die die Produktion von Fahrrädern speichert und die wir im JTree präsentieren und zur Laufzeit auch verändern wollen.
Um ein eigenes TreeModel zu implementieren, müssen wir nun also erstmal das TreeModel
-Interface implementieren und damit alle von ihm vorgeschriebenen Methoden überschreiben:
public BicycleTreeModel implements TreeModel {
@Override
public Object getChild(Object parent, int index) {
}
@Override
public int getChildCount(Object parent) {
}
@Override
public int getIndexOfChild(Object parent, Object child) {
}
@Override
public Object getRoot() {
}
@Override
public boolean isLeaf(Object node) {
}
@Override
public void addTreeModelListener(TreeModelListener l) {
}
@Override
public void removeTreeModelListener(TreeModelListener l) {
}
@Override
public void valueForPathChanged(TreePath path, Object newValue) {
}
}
TreeModelListener verwalten
Komponenten wie der JTree interessieren sich für das Geschehen in einem TreeModel und lauschen auf Ereignisse, die sich durch Benutzeraktionen ergeben. Das kann z. B. das Hinzufügen, Ändern oder Löschen von Datenelementen im TreeModel sein.
Damit ein Ereignis-Interessent (TreeModelListener
) die Benachrichtigungen über TreeModelEvent
s abonieren kann, muss er sich als Abonent registrieren.
Mit der Klasse EventListenerList
gibt es in Java bereits eine fertige Ereignis-Lauscher-Liste, die für alle möglichen [...]ModelListener-Typen eingesetzt werden kann.
Im Folgenden kümmern wir uns also darum, dass wir diese EventListenerList in unser TreeModel einbauen und auch die Möglichkeit schaffen, dass sich Interessenten für die Benachrichtigung über TreeModelEvents an unserem "Abo-Dienst" anmelden und auch von ihm wieder abmelden können.
Zeit, um den bereits implementierten Methoden addTreeModelListener(TreeModelListener l)
und removeTreeModelListener(TreeModelListener l)
etwas Code zu geben!
public BicycleTreeModel implements TreeModel {
private final EventListenerList listeners;
[...]
@Override
public void addTreeModelListener(TreeModelListener l) {
listeners.remove(TreeModelListener.class, listener);
}
@Override
public void removeTreeModelListener(TreeModelListener l) {
listeners.add(TreeModelListener.class, listener);
}
[...]
}
Ein Konstruktor für unser TreeModel
Wie wir oben bereits angenommen haben, haben wir vielleicht schon eine Datenstruktur, die die Produktion von Fahrrädern verwaltet und speichert. Dann sollte unser Konstruktor per Parameter diese Datenstruktur auch übernehmen, um sie dann in unserem TreeModel weiter auslesen, und beschreiben zu können. Vorteil hier; ohne unsere Datenstruktur anpassen zu müssen, können wir diese nun auch über den JTree verwalten und vor allem darstellen.
public BicycleTreeModel implements TreeModel {
private final EventListenerList listeners;
private final BicycleProduction production;
public BicycleTreeModel(BicycleProduction production) {
listeners = new EventListenerList();
this.production = production;
}
[...]
}
getRoot()-Methode implementieren
Weiter geht es mit der Implementierung der TreeModel-Methoden. Schrittweise werden wir nun die Methoden mit sinnvollem Code füllen.
Die getRoot()-Methode soll den Wurzelknoten des Baumes zurückgeben. Die Verknüpfung von Elementen aus unserer bestehenden Datenstruktur mit einem Baumknoten kann recht einfach wie komfortabel über die von der API bereitgestellten Klasse DefaultMutableTreeNode
erledigt werden. Mehr dazu im großen JTree (Tutorial)©.
public BicycleTreeModel implements TreeModel {
private final EventListenerList listeners;
private final BicycleProduction production;
private final DefaultMutableTreeNode root;
public BicycleTreeModel(BicycleProduction production) {
listeners = new EventListenerList();
this.production = production;
root = new DefaultMutableTreeNode(production.getPeriod());
for (Bicycle bicycle : production.getBicycleList()) {
root.add(new DefaultMutableTreeNode(bicycle));
}
}
/**
* @see javax.swing.tree.TreeModel#getRoot()
*/
@Override
public Object getRoot() {
return root;
}
[...]
}
Dieser Beitrag wird derzeit noch bearbeitet. Der Text ist deshalb unvollständig und kann Fehler oder ungeprüfte Aussagen enthalten. |