From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001
From: Sven Eisenhauer
+Nach JTable
+ist JTree
+die zweite der »großen« Elementarkomponenten in Swing.
+Sie dient zur Darstellung, Navigation und Bearbeitung baumartiger,
+hierarchischer Datenstrukturen.
+
+
+Ein einfaches Beispiel für derartige Baumstrukturen stellt etwa
+das Dateisystem unter UNIX oder Windows dar. Es besteht aus einer
+Wurzel (dem Root-Verzeichnis) und darin enthaltenen Unterverzeichnissen.
+Die Unterverzeichnisse können ihrerseits weitere Unterverzeichnisse
+enthalten usw. Dadurch entsteht eine beliebig tief geschachtelte Struktur
+von Verzeichnissen, die baumartig durchlaufen und bearbeitet werden
+kann. Andere Beispiele für Baumstrukturen sind die syntaktischen
+Elemente einer Programmiersprache, die Aufbauorganisation eines Unternehmens
+oder das Inhaltsverzeichnis in einem Buch.
+
+
+Im Umgang mit Bäumen haben sich folgende Begriffe eingebürgert:
+
+Der eigentliche Aufwand beim Erzeugen eines Baums liegt im Aufbau
+eines passenden Datenmodells, das seiner Struktur nach meist ebenfalls
+hierarchisch ist. Das Instanzieren des JTree
+ist dann vergleichsweise einfach. Die beiden wichtigsten Konstruktoren
+der Klasse JTree
+sind:
+
+
+Der erste von beiden erwartet ein vordefiniertes TreeModel
+zur Darstellung der Elemente des Baums. Ein TreeModel
+kapselt alle relevanten Informationen über die Struktur des Baums.
+Es liefert auf Anfrage dessen Wurzel, stellt Informationen über
+einen bestimmten Knoten zur Verfügung oder liefert dessen Unterknoten.
+
+
+An den zweiten Konstruktor wird lediglich die Wurzel des Baums übergeben.
+Sie wird vom Konstruktor automatisch in ein geeignetes TreeModel
+eingebettet. Beide Varianten sind prinzipiell gleichwertig. Zwar erfragt
+der JTree
+die zur Darstellung und Navigation erforderlichen Daten immer beim
+TreeModel.
+Aber das mit der Baumwurzel des zweiten Konstruktors instanzierte
+DefaultTreeModel
+ist in der Lage, diese Informationen aus den Knoten und den darin
+gespeicherten Verweisen auf ihre Unterknoten zu entnehmen (alle nötigen
+Informationen werden in den TreeNodes
+selbst gehalten). Wir werden später auf beide Arten, Bäume
+zu konstruieren, noch genauer eingehen.
+
+
+Ein JTree
+besitzt nicht so viele Konfigurationsoptionen wie eine JTable.
+Die wichtigste von ihnen regelt, ob die Wurzel des Baums bei seiner
+Darstellung angezeigt oder unterdrückt werden soll. Auf sie kann
+mit den Methoden setRootVisible
+und isRootVisible
+zugegriffen werden:
+
+
+Wir wollen uns zunächst ein einfaches Beispiel ansehen. Das folgende
+Programm erzeugt eine rekursive Baumstruktur mit Wurzel und zwei Unterebenen,
+deren Knoten aus Objekten des Typs DefaultMutableTreeNode
+bestehen. Diese im Paket javax.swing.tree
+gelegene Klasse ist eine Standardimplementierung des TreeNode-Interfaces,
+das beschreibt, wie ein Knoten Informationen über seine Unter-
+und Vaterknoten zur Verfügung stellen kann. Die vier wichtigsten
+Methoden von TreeNode
+sind:
+
+
+Mit getChildCount
+kann die Anzahl der Unterknoten ermittelt werden. Sie werden von 0
+an durchnummeriert, getChildAt
+liefert einen beliebigen Unterknoten. Ein Knoten kennt seinen Vaterknoten,
+der mit getParent
+ermittelt werden kann. Mit isLeaf
+kann zudem abgefragt werden, ob ein Knoten ein Blatt ist oder weitere
+Unterknoten enthält. Zur Beschriftung des Knotens bei der visuellen
+Darstellung verwendet ein JTree
+die Methode toString
+der Knotenklasse.
+
+
+Mit DefaultMutableTreeNode
+steht eine recht flexible Implementierung von TreeNode
+zur Verfügung, die auch Methoden zum Einfügen und Löschen
+von Knoten bietet (sie implementiert übrigens das aus TreeNode
+abgeleitete Interface MutableTreeNode):
+
+
+Mit add
+wird ein neuer Kindknoten an das Ende der Liste der Unterknoten angefügt,
+mit insert
+kann dies an einer beliebigen Stelle erfolgen. remove
+entfernt einen beliebigen und removeAllChildren
+alle Kindknoten. Anwendungsbezogene Informationen werden in einem
+UserObject gehalten, das direkt an den Konstruktor übergeben
+werden kann. Mit setUserObject
+und getUserObject
+kann auch nach der Konstruktion noch darauf zugegriffen werden. Das
+UserObject ist auch der Lieferant für die Knotenbeschriftung:
+jeder Aufruf von toString
+wird an das UserObject weitergeleitet.
+
+
+DefaultMutableTreeNode
+stellt noch weitaus mehr als die hier beschriebenen Methoden zur Verfügung.
+Die Klasse ist sehr vielseitig und kann auch unabhängig von der
+Verwendung in einem JTree
+zum Aufbau und zur Verarbeitung baumartiger Datenstrukturen verwendet
+werden.
+Das folgende Programm erzeugt eine Wurzel mit fünf Unterknoten,
+die jeweils drei weitere Unterknoten enthalten. Anschließend
+wird der Wurzelknoten an den Konstruktor eines JTree
+übergeben und dieser durch Einbetten in eine JScrollPane
+(um automatisches Scrollen zu ermöglichen) in einem JFrame
+platziert.
+
+
+
+
+
+
+ Titel
+ Inhalt
+ Suchen
+ Index
+ DOC
+ Handbuch der Java-Programmierung, 5. Auflage
+
+ <<
+ <
+ >
+ >>
+ API
+ Kapitel 38 - Swing: Komponenten II
+
+
+
+
+
+38.3 JTree
+
+
+
+
+
+
+
+
+38.3.1 Erzeugen eines Baums
+
+
+
+
+
+
+
+
+
+
+
+
+
+public JTree(TreeModel newModel)
+public JTree(TreeNode root)
+
+
+
+javax.swing.JTree
+
+
+
+
+
+
+
+
+
+public void setRootVisible(boolean rootVisible)
+public boolean isRootVisible()
+
+
+
+javax.swing.JTree
+
+
+
+
+
+
+
+
+
+public int getChildCount()
+public TreeNode getChildAt(int childIndex)
+
+public TreeNode getParent()
+
+public boolean isLeaf()
+
+
+
+javax.swing.tree.TreeNode
+
+
+
+
+
+
+
+
+
+public DefaultMutableTreeNode(Object userObject)
+
+public void add(MutableTreeNode newChild)
+public void insert(MutableTreeNode newChild, int childIndex)
+public void remove(int childIndex)
+public void removeAllChildren()
+
+public void setUserObject(Object userObject)
+public Object getUserObject()
+
+
+
+javax.swing.tree.DefaultMutableTreeNode
+
+
+
+
+
+
+
+![]()
+
+![]()
+
+
+
+![]()
+
+
+
+
+
+ Tipp
+
+
+
+
+Listing 38.11: Ein einfacher JTree
+
+
+
+
+
+001 /* Listing3811.java */
+002
+003 import java.awt.*;
+004 import java.awt.event.*;
+005 import javax.swing.*;
+006 import javax.swing.tree.*;
+007
+008 public class Listing3811
+009 extends JFrame
+010 {
+011 public Listing3811()
+012 {
+013 super("JTree 1");
+014 addWindowListener(new WindowClosingAdapter(true));
+015 //Einfaches TreeModel bauen
+016 DefaultMutableTreeNode root, child, subchild;
+017 root = new DefaultMutableTreeNode("Root");
+018 for (int i = 1; i <= 5; ++i) {
+019 String name = "Child-" + i;
+020 child = new DefaultMutableTreeNode(name);
+021 root.add(child);
+022 for (int j = 1; j <= 3; ++j) {
+023 subchild = new DefaultMutableTreeNode(name + "-" + j);
+024 child.add(subchild);
+025 }
+026 }
+027 //JTree erzeugen
+028 JTree tree = new JTree(root);
+029 tree.setRootVisible(true);
+030 //JTree einfügen
+031 Container cp = getContentPane();
+032 cp.add(new JScrollPane(tree), BorderLayout.CENTER);
+033 }
+034
+035 public static void main(String[] args)
+036 {
+037 Listing3811 frame = new Listing3811();
+038 frame.setLocation(100, 100);
+039 frame.setSize(250, 200);
+040 frame.setVisible(true);
+041 }
+042 }
+
+
+Listing3811.java
+
+Mit aufgeklapptem zweiten und vierten Knoten sieht das Programm wie +in Abbildung 38.9 dargestellt +aus. Auf der linken Seite wird der Baum im Metal-, auf der rechten +im Windows-Look-and-Feel gezeigt. +
+ +
+Abbildung 38.9: Ein einfacher JTree im Metal- und Windows-Look-and-Feel
+ + + + ++Das Selektieren von Knoten wird durch das TreeSelectionModel +gesteuert, auf das mit Hilfe der Methoden setSelectionModel +und getSelectionModel +zugegriffen werden kann: +
+
+
++public void setSelectionModel(TreeSelectionModel selectionModel) +public TreeSelectionModel getSelectionModel() ++ + |
++javax.swing.JTree | +
+Standardmäßig erlaubt ein JTree +das Selektieren mehrerer Knoten. Soll die Selektionsmöglichkeit +auf einen einzelnen Knoten beschränkt werden, muss ein eigenes +TreeSelectionModel +an setSelectionModel +übergeben werden. Dazu kann eine Instanz der Klasse DefaultTreeSelectionModel +erzeugt und durch Aufruf von setSelectionMode +und Übergabe einer der Konstanten SINGLE_TREE_SELECTION, +CONTIGUOUS_TREE_SELECTION +oder DISCONTIGUOUS_TREE_SELECTION +konfiguriert werden: +
+
+
++public void setSelectionMode(int mode) ++ + |
++javax.swing.tree.DefaultTreeSelectionModel | +
+JTree +stellt eine Reihe von Methoden zur Verfügung, mit denen abgefragt +werden kann, ob und welche Knoten selektiert sind. Die wichtigsten +von ihnen sind: +
+
+
++public TreePath getSelectionPath() +public TreePath[] getSelectionPaths() + +public TreePath getLeadSelectionPath() ++ + |
++javax.swing.JTree | +
+Mit getSelectionPath +wird das selektierte Element ermittelt. Bei aktivierter Mehrfachselektion +liefert die Methode das erste aller selektierten Elemente. Ist kein +Knoten selektiert, wird null +zurückgegeben. getSelectionPaths +gibt ein Array mit allen selektierten Knoten zurück. getLeadSelectionPath +liefert das markierte Element. + +
+Alle beschriebenen Methoden liefern Objekte des Typs TreePath. +Diese Klasse beschreibt einen Knoten im Baum über den Pfad, der +von der Wurzel aus beschritten werden muss, um zu dem Knoten zu gelangen. +Mit getLastPathComponent +kann das letzte Element dieses Pfads bestimmt werden. In unserem Fall +ist das gerade der selektierte Knoten. Mit getPath +kann der komplette Pfad ermittelt werden. An erster Stelle liegt dabei +die Wurzel des Baums, an letzter Stelle das selektierte Element: +
+
+
++public Object getLastPathComponent() +public Object[] getPath() ++ + |
++javax.swing.tree.TreePath | +
+Soll ermittelt werden, ob und welche Elemente im Baum selektiert sind, +können die Methoden isSelectionEmpty +und isPathSelected +aufgerufen werden: +
+
+
++public boolean isSelectionEmpty() +public boolean isPathSelected(TreePath path) ++ + |
++javax.swing.JTree | +
+
![]() |
+
+
+ +Alternativ zum TreePath +kann auf die selektierten Elemente auch mit Hilfe ihrer internen Zeilennummer +zugriffen werden. Dazu besitzt jedes angezeigte Element im +Baum eine fortlaufende Nummer, die mit 0 bei der Wurzel beginnt und +sich dann zeilenweise bis zum letzten Element fortsetzt. Die zugehörigen +Methoden heißen getSelectionRows +und getLeadSelectionRow. +Abhängig davon, wie viele Knoten oberhalb eines bestimmten Knotens +sichtbar oder verdeckt sind, kann sich die Zeilennummer während +der Lebensdauer des Baums durchaus verändern, und es gibt Methoden, +um zwischen Knotenpfaden und Zeilennummern zu konvertieren. Wir wollen +auf dieses Konzept nicht weiter eingehen. |
+
+
|
+![]() |
+
+Dient der JTree +zur Steuerung anderer Komponenten (etwa in explorerartigen Oberflächen), +muss das Programm meist unmittelbar auf Änderungen der Selektion +durch den Anwender reagieren. Dazu kann es einen TreeSelectionListener +instanzieren und ihn mit addTreeSelectionListener +beim JTree +registrieren. Bei jeder Selektionsänderung wird dann die Methode +valueChanged +aufgerufen und bekommt ein TreeSelectionEvent +als Argument übergeben: +
+
+
++public void valueChanged(TreeSelectionEvent event) ++ + |
++javax.swing.event.TreeSelectionListener | +
+Dieses stellt unter anderem die Methoden getOldLeadSelectionPath +und getNewLeadSelectionPath +zur Verfügung, um auf den vorherigen oder aktuellen Selektionspfad +zuzugreifen: +
+
+
++public TreePath getOldLeadSelectionPath() +public TreePath getNewLeadSelectionPath() ++ + |
++javax.swing.event.TreeSelectionEvent | +
+Das folgende Programm erweitert Listing 38.11 +um die Fähigkeit, das selektierte Element auf der Konsole auszugeben. +Dazu definiert es ein TreeSelectionModel +für Einfachselektion und fügt einen TreeSelectionListener +hinzu, der jede Selektionsänderung dokumentiert: + + +
+
+
+
+001 /* Listing3812.java */
+002
+003 import java.awt.*;
+004 import java.awt.event.*;
+005 import javax.swing.*;
+006 import javax.swing.event.*;
+007 import javax.swing.tree.*;
+008
+009 public class Listing3812
+010 extends JFrame
+011 {
+012 public Listing3812()
+013 {
+014 super("JTree 2");
+015 addWindowListener(new WindowClosingAdapter(true));
+016 //Einfaches TreeModel bauen
+017 DefaultMutableTreeNode root, child, subchild;
+018 root = new DefaultMutableTreeNode("Root");
+019 for (int i = 1; i <= 5; ++i) {
+020 String name = "Child-" + i;
+021 child = new DefaultMutableTreeNode(name);
+022 root.add(child);
+023 for (int j = 1; j <= 3; ++j) {
+024 subchild = new DefaultMutableTreeNode(name + "-" + j);
+025 child.add(subchild);
+026 }
+027 }
+028 //JTree erzeugen und Einfachselektion aktivieren
+029 JTree tree = new JTree(root);
+030 TreeSelectionModel tsm = new DefaultTreeSelectionModel();
+031 tsm.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+032 tree.setSelectionModel(tsm);
+033 tree.setRootVisible(true);
+034 //JTree einfügen
+035 Container cp = getContentPane();
+036 cp.add(new JScrollPane(tree), BorderLayout.CENTER);
+037 //TreeSelectionListener hinzufügen
+038 tree.addTreeSelectionListener(
+039 new TreeSelectionListener()
+040 {
+041 public void valueChanged(TreeSelectionEvent event)
+042 {
+043 TreePath tp = event.getNewLeadSelectionPath();
+044 if (tp != null) {
+045 System.out.println(" Selektiert: " + tp.toString());
+046 } else {
+047 System.out.println(" Kein Element selektiert");
+048 }
+049 }
+050 }
+051 );
+052 }
+053
+054 public static void main(String[] args)
+055 {
+056 try {
+057 Listing3812 frame = new Listing3812();
+058 frame.setLocation(100, 100);
+059 frame.setSize(250, 200);
+060 frame.setVisible(true);
+061 } catch (Exception e) {
+062 }
+063 }
+064 }
+
+ |
++Listing3812.java | +
+Die Selektion kann auch programmgesteuert verändert werden: +
+
+
++public void clearSelection() + +public void addSelectionPath(TreePath path) +public void addSelectionPaths(TreePath[] paths) + +public void setSelectionPath(TreePath path) +public void setSelectionPaths(TreePath[] paths) ++ + |
++javax.swing.JTree | +
+Mit clearSelection +wird die Selektion vollständig gelöscht. Mit addSelectionPath +und addSelectionPaths +kann die Selektion um ein einzelnes oder eine Menge von Knoten erweitert +werden. Mit setSelectionPath +und setSelectionPaths +werden - unabhängig von der bisherigen Selektion - die als Argument +übergebenen Knoten selektiert. + + + + +
+Der Anwender kann die Knoten mit Maus- oder Tastaturkommandos öffnen +oder schließen. Dadurch werden die Unterknoten entweder sichtbar +oder versteckt. Das Programm kann diesen Zustand mit den Methoden +isCollapsed +und isExpanded +abfragen: +
+
+
++public boolean isExpanded(TreePath path) +public boolean isCollapsed(TreePath path) + +public boolean hasBeenExpanded(TreePath path) + +public boolean isVisible(TreePath path) +public void makeVisible(TreePath path) + +public void expandPath(TreePath path) +public void collapsePath(TreePath path) ++ + |
++javax.swing.JTree | +
+isExpanded +liefert true, +wenn der Knoten geöffnet ist, isCollapsed, +wenn er geschlossen ist. hasBeenExpanded +gibt an, ob der Knoten überhaupt schon einmal geöffnet wurde. +isVisible +gibt genau dann true +zurück, wenn der Knoten sichtbar ist, d.h. wenn alle seine Elternknoten +geöffnet sind. Mit makeVisible +kann ein Knoten sichtbar gemacht werden. Mit expandPath +kann er geöffnet und mit collapsePath +geschlossen werden. + + + + +
+Es ist ohne weiteres möglich, den Inhalt und die Struktur des +Baums nach dem Anlegen des JTree +zu ändern. Es können neue Knoten eingefügt, bestehende +entfernt oder vorhandene modifiziert werden. Wird die Klasse DefaultMutableTreeNode +als Knotenklasse verwendet, reicht es allerdings nicht aus, einfach +die entsprechenden Methoden zum Ändern, Einfügen oder Löschen +auf den betroffenen Knoten aufzurufen. In diesem Fall würde zwar +die Änderung im Datenmodell durchgeführt werden, aber die +Bildschirmdarstellung würde sich nicht verändern. + +
+Änderungen im Baum müssen immer über das Modell ausgeführt +werden, denn nur dort ist der JTree +standardmäßig als TreeModelListener +registriert und wird über Änderungen unterrichtet. Werden +diese dagegen direkt auf den Knoten ausgeführt, bleiben sie dem +Modell verborgen und die Anzeige wird inkonsistent. + +
+Für einfache Änderungen reicht es aus, eine Instanz der +Klasse DefaultTreeModel +als TreeModel +zu verwenden. Sie wird durch Übergabe des Wurzelknotens instanziert +und stellt eine Vielzahl von Methoden zum Einfügen, Löschen +und Ändern der Knoten zur Verfügung. Alle Änderungen +werden durch Versenden eines TreeModelEvent +automatisch an alle registrierten TreeModelListener +weitergegeben und führen dort zu entsprechenden Aktualisierungen +der Bildschirmdarstellung. + +
+Die zum Ändern des Modells benötigten Methoden von DefaultTreeModel +sind: +
+
+
++public void insertNodeInto( + MutableTreeNode newChild, + MutableTreeNode parent, + int index +) + +public void removeNodeFromParent(MutableTreeNode node) + +public void nodeChanged(TreeNode node) + +public TreeNode[] getPathToRoot(TreeNode aNode) ++ + |
++javax.swing.tree.DefaultTreeModel | +
+Mit insertNodeInto +wird ein neuer Kindknoten an einer beliebigen Position zu einem Elternknoten +hinzugefügt. Mit removeNodeFromParent +wird ein beliebiger Knoten aus dem Baum entfernt (er darf auch Unterknoten +enthalten), und nodeChanged +sollte aufgerufen werden, wenn der Inhalt eines Knotens sich so geändert +hat, dass seine Bildschirmdarstellung erneuert werden muss. getPathToRoot +schließlich ist eine nützliche Hilfsmethode, mit der das +zur Konstruktion eines TreePath-Objekts +erforderliche Knoten-Array auf einfache Weise erstellt werden kann. + +
+Das folgende Programm zeigt einen Baum, der zunächst nur den +Wurzelknoten enthält. Dieser ist vom Typ DefaultMutableTreeNode +und wird in ein explizit erzeugtes DefaultTreeModel +eingebettet, dass an den Konstruktor des JTree +übergeben wird. Neben dem JTree +enthält das Programm drei Buttons, mit denen ein neuer Knoten +eingefügt sowie ein vorhandener gelöscht oder seine Beschriftung +geändert werden kann. + + +
+
+
+
+001 /* Listing3813.java */
+002
+003 import java.awt.*;
+004 import java.awt.event.*;
+005 import javax.swing.*;
+006 import javax.swing.event.*;
+007 import javax.swing.tree.*;
+008
+009 public class Listing3813
+010 extends JFrame
+011 implements ActionListener
+012 {
+013 protected DefaultMutableTreeNode root;
+014 protected DefaultTreeModel treeModel;
+015 protected JTree tree;
+016
+017 public Listing3813()
+018 {
+019 super("JTree 3");
+020 addWindowListener(new WindowClosingAdapter(true));
+021 //JTree erzeugen und Einfachselektion aktivieren
+022 root = new DefaultMutableTreeNode("Root");
+023 treeModel = new DefaultTreeModel(root);
+024 tree = new JTree(treeModel);
+025 TreeSelectionModel tsm = new DefaultTreeSelectionModel();
+026 tsm.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+027 tree.setSelectionModel(tsm);
+028 tree.setRootVisible(true);
+029 //JTree einfügen
+030 Container cp = getContentPane();
+031 cp.add(new JScrollPane(tree), BorderLayout.CENTER);
+032 //ButtonPanel
+033 JPanel panel = new JPanel(new FlowLayout());
+034 String[] buttons = new String[]{"AddChild", "Delete", "Change"};
+035 for (int i = 0; i < buttons.length; ++i) {
+036 JButton button = new JButton(buttons[i]);
+037 button.addActionListener(this);
+038 panel.add(button);
+039 }
+040 cp.add(panel, BorderLayout.SOUTH);
+041 }
+042
+043 public void actionPerformed(ActionEvent event)
+044 {
+045 String cmd = event.getActionCommand();
+046 TreePath tp = tree.getLeadSelectionPath();
+047 if (tp != null) {
+048 DefaultMutableTreeNode node;
+049 node = (DefaultMutableTreeNode)tp.getLastPathComponent();
+050 if (cmd.equals("AddChild")) {
+051 DefaultMutableTreeNode child;
+052 child = new DefaultMutableTreeNode("child");
+053 treeModel.insertNodeInto(child, node, node.getChildCount());
+054 TreeNode[] path = treeModel.getPathToRoot(node);
+055 tree.expandPath(new TreePath(path));
+056 } else if (cmd.equals("Delete")) {
+057 if (node != root) {
+058 TreeNode parent = node.getParent();
+059 TreeNode[] path = treeModel.getPathToRoot(parent);
+060 treeModel.removeNodeFromParent(node);
+061 tree.setSelectionPath(new TreePath(path));
+062 }
+063 } else if (cmd.equals("Change")) {
+064 String name = node.toString();
+065 node.setUserObject(name + "C");
+066 treeModel.nodeChanged(node);
+067 }
+068 }
+069 }
+070
+071 public static void main(String[] args)
+072 {
+073 try {
+074 String plaf = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
+075 UIManager.setLookAndFeel(plaf);
+076 Listing3813 frame = new Listing3813();
+077 frame.setLocation(100, 100);
+078 frame.setSize(300, 300);
+079 frame.setVisible(true);
+080 } catch (Exception e) {
+081 }
+082 }
+083 }
+
+ |
++Listing3813.java | +
+Alle Button-Aktionen werden in actionPerformed +ausgeführt. Darin wird zunächst das Action-Kommando abgefragt +und dann in Zeile 046 +der Pfad des selektierten Elements bestimmt. Ist dieser nicht leer, +werden die Kommandos wie folgt ausgeführt: +
+Nach einigen Einfügungen, Änderungen und Löschungen +sieht die Programmausgabe beispielsweise so aus: +
+ +
+Abbildung 38.10: Ein veränderbarer JTree
+| Titel + | Inhalt + | Suchen + | Index + | DOC + | Handbuch der Java-Programmierung, 5. Auflage, Addison +Wesley, Version 5.0.1 + |
| << + | < + | > + | >> + | API + | © 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de + |