Übung 1a: Baumansichten der Java Foundation Classes "Model

Werbung
Algorithmen und Datenstrukturen
Übung 1a: Baumansichten der Java Foundation Classes
"Model-View-Controller"-Ansatz
Die Oberflächentechnik "Swing" (Paket javax.swing) umfasst eine Vielzahl mächtiger
Klassen, z.B. Baumansichten, Tabellen. Swing benutzt den "Model-View-Controller"Ansatz, d.h. eine konsequente Trennung der Daten und der Darstellung.
Beim MVC-Ansatz unterscheidet man 3 Arten von Applikationselementen:
- Model Datenmodell)
Im Datenmodell werden Funktionalität und Zustand gespeichert. Es kann Anfragen von Views über
seinen Zustand beantworten und Zustandsänderungen vom Controller oder anderen Objekten
bearbeiten.
- View (Darstellung: look)
Die Ansicht weiß nichts oder nur sehr wenig (über das Datenmodell) und stellt lediglich die Daten dar
- Controller (Steuerung: feel)
Die Steuerung stellt ein Modell der realen welt dar und reagiert auf Benutzereingaben von Maus,
Tastatur und anderen Eingabegeräten.
Ein "Model" kann mehrere "Views" gleichzeitig haben. Damit Veränderungen des
Modells in allen Views sichtbar werden, wird ein Benachrichtungsmechanismus
implementiert, mit dem das Modell die verschiedenen Views über Änderungen
informiert.
Bei praktische Realisierung führt die MVC-Architektur zu Problemen bzgl.
- der Entwicklung der Komponenten
Meistens sind View und Controller eng verbunden, so dass es zusätzlichen Schnittstellenaufwand für
die Implementierung gibt.
- erhöhter Kommunikationsaufwand zwischen Objekten.
Falls sich Ergebnisse in der Darstellung oder dem Modell ergeben, führt die Benachrichtigung immer
über den Controller.
Sinnvoll ist es daher View und Controller zu einer Komponente zu verschmelzen
(Vereinfachung der komplexen Interaktion zwischen View und Controller). Das neue
Modell wird anstatt MVC auch Model-View-Presenter (MVP-Pattern) genannt.
In Java ist der View und Controller durch ComponentUI repräsentiert. Für alle
Swing-Komponenten gibt es ein Component-Objekt, das Darstellung und
Benutzeraktion übernimmt.
Die Klasse JTree
Die Baumdarstellung basiert auf einem hierarchischen Datenmodell. Jede
Modellklasse zur Baumdarstellung muß sich auf das Interface TreeModel beziehen.
JTree besitzt dafür Konstruktoren bzw. die Zugriffsmethoden getModel() und
setModel(). Die einzelnen Baumknoten müssen die Interfaces TreeNode oder
MutableTreeNode implementieren. Die Klasse DefaulMutableTreeNode enthält
eine universelle Implementierung (inklusive Navigationsmethoden) für Baumknoten
Erzeugen eines Baums. Liegt ein geeignetes Datenmodell vor, ist das Instanzieren
eines JTree einfach. Die beiden wichtigsten Konstruktoren der Klasse JTree sind:
public JTree(TreeModel neuesModell)
// erwartet wird ein vordefiniertes TreeModel zur Darstellung der Baumelemente. Ein TreeModel
// kapselt alle relevanten Informationen über die Baumstruktur. Es liefert auf Anfrage die Wurzel
1
Algorithmen und Datenstrukturen
// des Baums, stellt Informationen über einen bestimmten Knoten bereit oder liefert dessen
// Nachfolgeknoten
public JTree(TreeNode wurzel)
// Die Wurzel wird automatisch in ein geeignetes TreeModel eingebettet. Der JTree erfragt die zur
// Darstellung der Navigation erforderlichen Daten immer beim TreeModel. Das über wurzel
// Baumwurzel) instanzierte DefaultTreeModel kann diese Informationen aus den Knoten und den
// darin gespeicherten Verweisen auf ihre Nachfolgeknoten entnehmen.
Zugriffsmethoden auf das Datenmodell.
public TreeModel getModel()
public void setModel(TreeModel neuesModell)
Anzeige bzw. Unterdrücken der Wurzel bei der Baumdarstellung. Eine wichtige
Konfigurationsoption regelt, ob die Wurzel des Baums bei seiner Darstellung
angezeigt oder unterdrückt werden soll. Auf sie kann mit den Methoden
public void setRootVisible(boolean rootVisible)
public boolean isRootVisible()
zugegriffen werden.
Zur Beschriftung eines Knotens bei der visuellen Darstellung verwendet ein JTree
die Methode toString().
Abfragen zur Selektion von Baumknoten. JTree stellt eine Reihe von Methoden für
Abfragen bereit, ob und welche Knoten selektiert sind, z.B.:
public TreePath getSelectionPath()
// ermittelt das selektierte Element. Bei aktivierter Mehrfachselektion liefert die Methode das erste aller
// selektierten Elemente. Falls kein Knoten selektiert ist, wird null zurückgeliefert.
public TreePath[] getSelectionPaths()
// zurückgegeben wird ein Array mit allen selektierten Knoten
public TreePath getLeadSelectionPath()
// liefert das markierte Element
Die angegebenen Methoden liefern Objekte der Klasse TreePath. Diese Klasse
beschreibt einen Knoten im Baum über den Pfad, der von der Wurzel aus beschritten
werden muß, um zu den Knoten zu gelangen. Mit
public Object getLastSelectedPathComponent()
der Klasse TreePath kann das letzte Element dieses Pfads bestimmt werden. Mit
public Object[] getPath()
der Klasse TreePath kann der vollständige Pfad ermittelt werden. An erster Stelle
liegt die Wurzel des Baums, an letzter Stelle das selektierte Element. Solle ermittelt
werden, ob und welche Elemente im Baum selektiert sind, können die Methoden
public boolean isSelectionEmpty()
public boolean isPathSelected(TreePath pfad)
aufgerufen werden.
Verändern der Selektion. Die Selektion kann programmgesteuert verändert werden:
public void clearSelection()
// Löschen der Selektion
public void addSelectionPath(TreePath path)
2
Algorithmen und Datenstrukturen
// Erweitern der Selektion um ein einzelnes Element
public void addSelectionPaths(TreePath [] pfade)
// Erweitern der Selektion um eine Menge Knoten
public void setSelectionPath(TreePath path)
// Selektion der als Argument übergebenen Knoten)
public void setSelectionPaths(TreePath[] paths)
// Selektion der als Argument übergebenen Knoten
Zur unmittelbaren Reaktion auf Änderungen der Selektion durch den Anwender kann
ein
TreeSelectionListener
instanziert
werden
(Registrierung
mit
addTreeSelectionListener() beim JTree). Bei jeder Selektionsänderung wird
public void valueChanged(TreeSelectionEvent event)
aufgerufen. "event" stellt
public TreePath getOldLeadSelectionPath()
public TreePath getNewLeadSelectionPath()
zur Verfügung, um auf den vorherigen und aktuellen Selektionspfad zuzugreifen.
Öffnen und Schließen der Knoten. Der Anwender kann die Knoten mit Maus- oder
Tastaturkommandos öffnen oder schließen. Dadurch werden Nachfolgeknoten
sichtbar oder versteckt.
public boolean isExpanded(TreePath pfad)
// liefert true, wenn der Knoten geöffnet ist
public boolean isCollapsed()
// liefert true, wenn der Knoten geschlossen ist
public boolean hasBeenExpanded(TreePath path)
// gibt an, ob der Knoten überhaupt schon einmal geöffnet wurde
public boolean isVisible(TreePath pfad)
// liefert true, wenn der Knoten sichtbar ist, d.h. all seine Elternknoten geöffnet sind
public void makeVisible(TreePath pfad)
// Sichtbar Machen eines Knoten
public void expandPath(TreePath pfad)
// Öffnen eines Knoten
public void collapsePath(TreePath pfad)
// Schließen eines Knoten
Verändern der Baumstruktur. Es können neue Knoten eingefügt, bestehende entfernt
oder vorhandene modifiziert werden.
Interfaces zur Modellierung und Sicht auf einen Baum
Drei Interfaces erlauben Modellierung und Sicht auf einen Baum: TreeModel,
TreeSelectionModel, TreeCellRenderer.
Ein viertes Interface TreeNode beschreibt, was in jedem Knoten des Baums
dargestellt wird.
TreeModel
Dieses Interface beschreibt das einem JTree zugeordnete Datenmodell. Das
TreeModel-Interface spezifiziert, wie ein Baum (über eine Datenstruktur) abgebildet
wird.
3
Algorithmen und Datenstrukturen
public Object getChild(Object parent, int index)
public int getChildCount(Object parent)
public int getIndexOfChild(Object parent,Object child)
public Object getRoot()
public Object isLeaf(Object node)
Drei weitere Methoden
public void addTreeModelListener(TreeModelListener l)
public void removeTreeModelListener(TreeMoldelListener l)
public void valueForPathChanged(TreePath pfad, Object neuerWert)
behandeln Hinzufügen, Entfernen und die Kentnisnahme von Event-Listeners. Diese
Listeners bemerken Änderungen im TreeModel nach Empfang von TreeModelEventNachrichten.
Ein Objekt, das diese Methoden definiert, kann Modell für einen JTree sein. Die
DefaultTreeModel-Klasse ist eine einfache Implementierung des TreeModel,
das explizit TreeNode- und MutableTreeNode-Objekte benutzt.
TreeNode
JTree-Objekte werden aus TreeNode-Objekten gebildet (einfache Repräsentationen
eines Baumknoten). Die wichtigsten Methoden von TreeNode sind:
public int getChildCount()
// ermittelt die Anzahl der Nachfolgeknoten. Sie werden von 0 an durchnummeriert.
public TreeNode getChildAt(int childIndex)
// liefert einen beliebigen Nachfolgeknoten
public TreeNode getParent()
// Ein Knoten kennt seinen Vaterknoten, der mit getParent() ermittelt werden kann
public boolean isLeaf()
// Abfrage, ob ein Knoten ein Blatt ist oder weitere Nachfolgeknoten enthält
Die Klasse DefaultMutableTreeNode definiert Methoden zum Anschauen und
Manipulieren von Baumknoten. Diese Klasse implementiert das Interface
MutableTreeNode (Extension des Interface TreeNode).
Anwendungsbezogene Informationen werden bereits dem Konstruktor übergeben:
public DefaultMutableTreeNode(Object benutzerObjekt)
DefaultMutableTreeNode hat Methoden zum Einfügen und Löschen von Knoten
implementiert:
public void add(MutableTreeNode neuesKind)
// ein Kindknoten wird an das Ende der Liste der Nachfolgeknoten angefügt
public void insert(MutableTreeNode neuesKind, int KindIndex)
// Einfügen eines neuen Kindknoten an beliebiger Stelle
public void remove(int kindIndex)
// Entfernen eines beliebigen Knoten
public void removeAllChildren()
// Entfernen aller Kindknoten
/* Zugriff auf Infornationen, die in einem benutzerObjekt gehalten werden */
public void setUserObject(Object benutzerObjekt)
public Object getUserObject()
// benutzerObjekt ist auch der Lieferant von Knotenbeschriftungen. Jeder Aufruf von toString()
// wird an benutzerObjekt weitergeleitet
4
Algorithmen und Datenstrukturen
TreeSelectionModel
Diese Interface spezifiziert, wie ein Benutzer einen Pfad bestimmter Objekte
auswählen kann. JTree benutzt dieses Modell zur Auswahl von Regeln.
DefaultTreeSelectionModel
ist
eine
Implementierung
von
TreeSelectionModel.
TreeSelectionModel steuert das Selektieren von Knoten. Die Zugriffsmethoden
auf TreeSelectionModel sind:
public void setSelectionModel(TreeSelectionModel selectionModel)
public TreeSelectionModel getSelectionModel()
Standardmäßig erlaubt ein JTree das Selektieren mehrerer Knoten. Soll die
Selektionsmöglichkeit auf einen Knoten beschränk werden, muß ein eigenes
TreeSelectionModel an setSelectionModel() übergeben werden. Dazu
kann eine Instanz der Klasse DefaultTreeSelectionModel erzeugt werden und
durch Aufruf von
public void setSelectionMode(int mode)
und Übergabe einer der Konstanten
SINGLE_TREE_SELECTION
CONTIGUOUS_TREE_SELECTION
DISCONTIGUOUS_TREE_SELECTION
konfiguriert werden.
TreeCellRenderer
Dieses Interface wird zur visuellen Repräsentation von Baumknoten benutzt. Es
umfasst nur eine Methode.
Anwendungen
1. Ein Baum, der aus DefaultMutableTreeNodes aufgebaut ist1.
import java.awt.*;
import javax.swing.*;
import javax.swing.tree.*;
/** Example tree built out of DefaultMutableTreeNodes.
* 1999 Marty Hall, http://www.apl.jhu.edu/~hall/java/
* Ueberarbeitet im Oktober 2002 Juergen S a u e r
*/
public class SimpleTree extends JFrame
{
public SimpleTree()
{
super("Creating a Simple JTree");
// WindowUtilities.setNativeLookAndFeel();
1
vgl. pr56570
5
Algorithmen und Datenstrukturen
/* try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
}
catch(Exception e)
{
System.out.println("Error setting native L&F: " + e);
} */
// addWindowListener(new ExitListener());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container content = getContentPane();
Object[] hierarchy =
{ "javax.swing",
"javax.swing.border",
"javax.swing.colorchooser",
"javax.swing.event",
"javax.swing.filechooser",
new Object[] { "javax.swing.plaf",
"javax.swing.plaf.basic",
"javax.swing.plaf.metal",
"javax.swing.plaf.multi" },
"javax.swing.table",
new Object[] { "javax.swing.text",
new Object[] { "javax.swing.text.html",
"javax.swing.text.html.parser" },
"javax.swing.text.rtf" },
"javax.swing.tree",
"javax.swing.undo" };
DefaultMutableTreeNode root = processHierarchy(hierarchy);
JTree tree = new JTree(root);
content.add(new JScrollPane(tree), BorderLayout.CENTER);
setSize(275, 300);
setVisible(true);
}
}
public static void main(String[] args)
{
new SimpleTree();
}
/** Small routine that will make node out of the first entry
* in the array, then make nodes out of subsequent entries
* and make them child nodes of the first one. The process is
* repeated recursively for entries that are arrays.
*/
private DefaultMutableTreeNode
processHierarchy(Object[] hierarchy)
{
DefaultMutableTreeNode node =
new DefaultMutableTreeNode(hierarchy[0]);
DefaultMutableTreeNode child;
for(int i=1; i<hierarchy.length; i++)
{
Object nodeSpecifier = hierarchy[i];
if (nodeSpecifier instanceof Object[])
// Knoten mit Nachfolgeknoten
child = processHierarchy((Object[])nodeSpecifier);
else
child = new DefaultMutableTreeNode(nodeSpecifier);
// Blatt
node.add(child);
}
return(node);
}
6
Algorithmen und Datenstrukturen
Swing besitzt einen Manager für Benutzerschnittstellen, der das "Look and Feel"
(Java L&F) von Komponenten kontrolliert. Das Management des Look and Feel wird
von der Klasse UIManager übernommen. Folgende Auswahlmöglichkeiten stehen in
Abhängigkeit von der Java-Entwicklungsumgebung zur Verfügung:
- das Windows-95- und Windows-NT-Look-and-Feel
- das Motif-x-Windows-System-Look-and-Feel
- Metal
Die
Auswahl
des
Look-and-Feel
erfolgt
mit
der
Methode
getSystemLookAndFeelClassName() als Argument für die Methode
setLookandFeel. Es werden unterschiedliche Ergebnisse auf unterschiedlichen
Betriebssystemen erzeugt.
7
Algorithmen und Datenstrukturen
Anlagen: Übersicht zur Klasse JTree und deren Modelle
JComponent
JTree
...
protected TreeCellEditor cellEditor
protected TreeCellRendrer cellRenderer
…
protected boolean rootVisible
protected TreeSelectionModel selectionModel
…
protected TreeModel treeModel
protected TreeModellListener treeModelListener
…
<< Konstruktoren >>
JTree()
JTree(Hashtable wert)
JTree(TreeModel neuesModel)
JTree(TreeNode root)
JTree(Vector wert)
JTree(Object[] wert)
…
<< Methoden >>
…
public void addSelectionPath(TreePath pfad)
public void addSelectionPaths(TreePath[] pfade)
public TreePath getSelectionPath()
// ermittelt das ausgewählte Element
public TreePath[] getSelectionPaths()
public void setSelectionPath(TreePath pfad)
public void setSelectionPaths(TreePath[] pfade)
public TreePath getLeadSelectionPath()
// liefert das markierte Element
…
public void setRootVisible(boolean rootVisible)
public boolean isRootVisible()
public TreeModel getModel()
public void setModel(TreeModel neuesModel)
public TreeCellRenderer getCellRenderer ()
public void setCellRenderer(TreeCellrenderer x)
…
public void setUI(TreeUI ui)
public void updateUI()
…
public void setSelectionModel(TreeSelectionModel selectionModel)
…
Abb.: Die Klasse JTree
8
Algorithmen und Datenstrukturen
<< interface >>
TreeModel
public Object getRoot()
public Object getChild(Object parent, int index)
public boolean isLeaf(Object knoten)
public void valueForPathChanged(TreePath pfad,Object neuerWert)
public int getIndexOfChild(Object parent, Object child)
public void addTreeModelListener(TreeModelListener l)
public void removeTreeListener(TreeModelListener l)
DefaultTreeModell
…
proteced TreeNode root
protected EventListenerList listenerList
<< Konstruktoren >>
public DefaultTreeModel()
public DefaultTreeModel(TreeNode root,boolean asksAllowsChildren)
<< Metoden >>
public void addTreeModelListener l)
public void removeTreeModelListener(TreeModelListener l)
…
public Object getChild(Object parent, int index)
public int getChildCount(Object parent)
public int getIndexOfChild(Object parent,Object child)
…
public TreeNode[] getPathToRoot(TreeNode einKnoten)
…
public Object getRoot()
….
public void insertInfo(MutableTreeNode neuesKind, MutableTreeNode
parent,int index)
public boolean isLeaf(Object knoten)
public void nodeChanged(TreeNode knoten)
…
public void removeNodeFromParent(MutableTreeNode knoten)
…
public void setRoot(TreeNode root)
public void valueForPathChanged(TreePath path,Object neuerWert)
9
Algorithmen und Datenstrukturen
<< interface >>
TreeSelectionModel
static int CONTIGUOUS_TREE_SELECTION
static int DISCONTIGUOUS_TREE_SELECTION
static int SINGLE_TREE_SELECTION
public void setSelectionMode(int node)
public int setSelectionPath(TreePath path)
public void setSelectionPaths(TreePath [] paths)
public void addSelectionPath(TreePath path)
public void addSelectionPaths(TreePath [] paths)
public void removeSelectionPath(TreePath path)
public void removeSelectionPaths(TreePaths [] paths)
public TreePath getSelectionPath()
public TreePath[] getSelectionPaths()
public int getSelectionCount()
public boolean isPathSelected(TreePath path)
public boolean isSelectionEmpty()
public void clearSelection()
public int [] getSelectionRows()
public boolean isRowSelected(int row)
public void resetRowSelection()
public int getLeadSelecttionRow()
public TreePath getSelectionPath()
public void addPropertyChangeListener(PropertyChangeListener listener)
DefaultTreeSelectionModel
...
protected int leadIndex
...
protected TreePath [] selection
…
static String SELECTION_MODE_PROPERTY
protected int selectionMode
…
<< Konstruktor >>
public DefaultTreeSelectionModel()
<< Methoden >>
public void addSelectionPath(TreePath path)
public void addSelectionPaths(TreePath [] paths)
public void removeSelectionPath(TreePath path)
…
public void addTreeSelectionListener(TreeSelectionListener x)
public void removeTreeSelectionListener(TreeSelectionListener x)
…
public void updateLeadIndex()
public void insureUniqueness
public String toString()
public Object clone() throws CloneNotSupportedException
10
Algorithmen und Datenstrukturen
<< interface >>
TreeNode
public Enumertion children()
public boolean getAllowsChildren()
public TreeNode getChildAt(int childIndex)
public int getChildCount()
public int getIndex(TreeNode node)
public TreeNode getParent()
public boolean isLeaf()
<< interface >>
MutableTreeNode
public void insert(MutableTreeNode child,int index)
public void remove(int index)
public void remove(MutableTreeNode node)
public void removeFromParent()
public void setParent(MutableTreeNode newParent)
public void setUserObject(Object objekt)
DefaultMutableTreeNode
….
protected MutableTreeNode parent
<< Konstruktoren >>
DefaultMutableTreeNode()
DefaultMutableTreeNode(Object objekt)
DefaultMutableTreeNode(Object benutzerObjekt)
<< Methoden >>
public void add(MutableTreeNode neuesKind)
public Enumeartion breadFirstEnumeration()
…
public Enumeration depthFirstEnumeration()
…
public TreeNode getChildAfter(TreeNode einKind)
…
public TreeNode getChildBefore(TreeNode einKind)
…
public int getDepth()
…
public int getLevel()
…
public TreeNode getPath()
protected TreeNode[] getPathToRoot(TreeNode einKnoten, int tiefe)
…
public TreeNode getRoot()
…
public boolean isRoot()
…
public void removeAllChildren()
…
public String toString()
11
Algorithmen und Datenstrukturen
<< interface >>
TreeCellEditor
public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected,
Boolean expanded, boolean leaf, int row)
DefaultTreeCellEditor
protected Color borderSelectionColor
protected booleab canEdit
protected Component editingComponent
protected Container editingContainer
protected Icob editingIcon
protected Font font
protected TreePath lstPath
…
protected Timer timer
protected JTree tree
<< Konstruktoren >>
public DefaultTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer)
public DefaultTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer,TreeCellEditor editor)
<< Methoden >>
public void setBorderSelectionColor(Color newColor)
public Color getBorderSelectionColor()
public void setFont(Font font)
public Font getFont()
…
12
Algorithmen und Datenstrukturen
<< interface >>
TreeCellRenderer
public Component getTreeCellRendererComponent( JTree tree, Object value, boolean selected,
boolean expanded, bollean leaf, int row,
boolean lostFocus)
DefaultTreeCellRenderer
protected Color backGroundSelectionColor
protected Color borderSelectionColor
protected Icon closedIcon
protected boolean hasFocus
protected Icon leafIcon
protected Icon openIcon
protected boolean selected
protected Color textNonSelectionColor
protected Color textSelectionColor
<< Konstruktor >>
public TreeCellRenderer()
<< Methoden >>
public void setFont(Font font)
public void setLeafIcon(Icon newIcon)
public void setOpenIcon(Icon newIcon)
public void setTextNonSelectionColor(Color newColor)
public void setTextSelectionColor(Color newColor)
public void validate()
13
Herunterladen