Kapitola 1. Stromy 1.1. Základní informace

Save this PDF as:
 WORD  PNG  TXT  JPG

Rozměr: px
Začít zobrazení ze stránky:

Download "Kapitola 1. Stromy 1.1. Základní informace"

Transkript

1 Kapitola 1. Stromy 1.1. Základní informace Strom (arbor) je růstová forma vyšších rostlin. Prýt (nadzemní část) stromu se skládá ze zdřevnatělé nevětvené spodní části - kmene, který se v určité výšce nad zemí dělí na jednotlivé větve (na rozdíl od keře, kde k větvení dochází již u země, nebo těsně nad zemí). Horní část stromu, kde dochází k větvení, se nazývá koruna. Přesnou definici pojmu strom (nebo keř) není možné vymezit kvůli velké diverzitě rostlin. Někdy je proto výhodnější používat termín stromovitá forma. Různý způsob větvení dává každému druhu charakteristický tvar. Tento tvar může být dále ovlivněn prostředím, ve kterém strom roste (zda roste osamoceně nebo uvnitř porostu - lesa). 1

2 2

3 V GUI je to komponenta, která zobrazuje hierarchická data základní třída javax.swing.jtree cca tucet podpůrných tříd a rozhraní jsou v balíku javax.swing.tree 3

4 kromě nich jsou v balíku javax.swing další podpůrné třídy a rozhraní společné i pro JTable CellEditor ListCellRenderer ListSelectionModel Renderer AbstractCellEditor 1.2. Základní princip je to velmi podobné JTable je nutné mít dvou (tří) stupňovou organizaci 1. na první (datové) úrovni je datový model typicky splňuje rozhraní javax.swing.tree.treemodel je to rozhraní mezi datovou a prezentační vrstvou naprosto nejjednodušší je použít DefaultTreeModel 2. na druhé (prezentační) úrovni je JTree jako vizuální komponenta typicky v konstruktoru přebírá datový model new JTree(mujTreeModel); Swing nepoužívá termíny datová a prezentační vrstva, ale model a view -- resp. nepoužívá ani termín view (ale myslí se to tak) Primitivní použití Termíny TBD node uzel root node from which all nodes descend kořen branch node nodes that can have children whether or not they currently have children leaf node node that can not have children expanded node non-leaf node (as identified by TreeModel.isLeaf(node) returning false) that will displays its children colapsed node one which hides its children hidden node under a collapsed ancestor 4

5 viewable nodes parents are expanded, but may or may not be displayed displayed node both viewable and in the display area node může být identifikován buď pomocí TreePath objektu nebo řádkou ve kterém se node nachází elementární příklad: //Where instance variables are declared: private JTree tree; public TreeDemo() { DefaultMutableTreeNode top = new DefaultMutableTreeNode("The Java Series"); createnodes(top); tree = new JTree(top); JScrollPane treeview = new JScrollPane(tree); přidání uzlů je intuitivní private void createnodes(defaultmutabletreenode top) { DefaultMutableTreeNode category = null; DefaultMutableTreeNode book = null; category = new DefaultMutableTreeNode("Books for Java Programmers"); top.add(category); //original Tutorial book = new DefaultMutableTreeNode(new BookInfo 5

6 ("The Java Tutorial: A Short Course on the Basics", "tutorial.html")); category.add(book); //Tutorial Continued book = new DefaultMutableTreeNode(new BookInfo ("The Java Tutorial Continued: The Rest of the JDK", "tutorialcont.html")); category.add(book); parametrem konstruktoru DefaultMutableTreeNode je tzv. user object -- to je buď String nebo objekt který má vhodně překrytou metody tostring Události pokud není možné překrýt tostring (například protože tostring je využíváne v programu i někde jinde, kde jsou na ni kladeny jiné požadavky než by se hodilo v JTree), tak se musí přetížit (přepsat defaultní) metoda convertvaluetotext třídy JTree. není třeba řešit expand a collapse funkcionalitu naopak je třeba řešit co se stane když uživatel vybere nějakou položku: nastavíte selection mode implementujete posluchače a zaregistrujete ho v posluchači implementujete metodu valuechanged (nebo jinou - v závislosti na vybranem selection módu) //Where the tree is initialized: tree.getselectionmodel().setselectionmode (TreeSelectionModel.SINGLE_TREE_SELECTION); //Listen for when the selection changes. tree.addtreeselectionlistener(this); public void valuechanged(treeselectionevent e) { // Returns the last path element of the selection. // This method is useful only when the selection // model allows a single selection. DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getlastselectedpathcomponent(); if (node == null) return; //Nothing is selected. 6

7 Object nodeinfo = node.getuserobject(); if (node.isleaf()) { BookInfo book = (BookInfo)nodeInfo; displayurl(book.bookurl); // TOHLE je ta užitečná akce kterou chceme provést else { displayurl(helpurl); // i TOHLE je ta užitečná akce kterou chceme provést Změna vzhledu metoda setrootvisible(true) metoda setshowsroothandles(true) metoda tree.putclientproperty("jtree.linestyle", "Horizontal"); pro změnu ikony se (podobně jako u JTable) používá render čili zobrazovač -- třída implementující rozhraní TreeCellRenderer -- standardně DefaultTreeCellRenderer a jeho tři metody: setleaficon (for leaf nodes) setopenicon (for expanded branch nodes) setclosedicon (for collapsed branch nodes) ImageIcon leaficon = createimageicon("images/middle.gif"); // viz 3/4 přednáška if (leaficon!= null) { DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer(); renderer.setleaficon(leaficon); tree.setcellrenderer(renderer); pro tool tip je třeba oddědit od DefaultTreeCellRenderer a překrýt metodu gettree- CellRendererComponent protože DefaultTreeCellRenderer je potřída JLabel lze používat metody jako seticon, settooltiptext a další 7

8 1.3. Změny ve stromu pro dynamické přidáváni a ubírání uzlů, například: inicializace stromu: rootnode = new DefaultMutableTreeNode("Root Node"); treemodel = new DefaultTreeModel(rootNode); treemodel.addtreemodellistener(new MyTreeModelListener()); // moje vlastní třída tree = new JTree(treeModel); tree.seteditable(true); // < tree.getselectionmodel().setselectionmode (TreeSelectionModel.SINGLE_TREE_SELECTION); tree.setshowsroothandles(true); TADY model je instance třídy DefaultMutableTreeNode a díky kouzelnému slovíčku mutable lze používat metody jako insertnodeinto (tato metoda není deklarovana v jednodušším rozhraní TreeModel) Poznámka Ačkoliv DefaultMutableTreeNode má metodu pro změnu obsahu uzlu, je třeba poslat změnu přes metody třídy DeafultTreeModel, jinak se nevygenerují příslušné události a posluchači (jako např. strom sám) by se o změně nedozvědeli. Změna jména uzlu -- jak implementovat rozhraní TreeModelListener: class MyTreeModelListener implements TreeModelListener { public void treenodeschanged(treemodelevent e) { /* * If the event lists children, then the changed * node is the child of the node we have already * gotten. Otherwise, the changed node and the * specified node are the same. */ try { int index = e.getchildindices()[0]; node = (DefaultMutableTreeNode) (node.getchildat(index)); catch (NullPointerException exc) { 8

9 System.out.println("The user has finished editing the node."); System.out.println("New value: " + node.getuserobject()); // typicky zde voláme metodu datové vrstvy -- uložení do DB, souboru a pod. public void treenodesinserted(treemodelevent e) { public void treenodesremoved(treemodelevent e) { public void treestructurechanged(treemodelevent e) { actionperformed obsluha události tlačítka Add: treepanel.addobject("new Node " + newnodesuffix++); dvojice metod addobject: public DefaultMutableTreeNode addobject(object child) { DefaultMutableTreeNode parentnode = null; TreePath parentpath = tree.getselectionpath(); if (parentpath == null) { //There is no selection. Default to the root node. parentnode = rootnode; else { parentnode = (DefaultMutableTreeNode) (parentpath.getlastpathcomponent()); return addobject(parentnode, child, true); public DefaultMutableTreeNode addobject(defaultmutabletreenode parent, Object child, boolean shouldbevisible) { DefaultMutableTreeNode childnode = new DefaultMutableTreeNode(child); treemodel.insertnodeinto(childnode, parent, parent.getchildcount()); //Make sure the user can see the lovely new node. if (shouldbevisible) { tree.scrollpathtovisible(new TreePath(childNode.getPath())); return childnode; 1.4. Datový model Může se stát, že defaultní implementace modelu nestačí 9

10 protože data nemají stromovou strukturu nebo mají stromovou strukturu, ale jinou, než chceme zobrazovat v JTree dobrá zpráva je, že TreeModel akceptuje libovolný Object (nikoliv povinně podtřídu DefaultMutableTreeNode nebo tak něco) tj. není nutné implementovat "další strom" jen proto že JTree vyžaduje TreeModel -- stačí vzít existující data (z datové vrstvy) a "obalit je" rozhraními (tj. zavázat se k implementaci rozhraní) [???] Dobrý příklad k prostudování je [ Lazy loading JTree má explicitní podporu pro lazy loading lazy loading je technika umožnující úsporu času a paměti za běhu programu nenačítají se data, pokud nejsou opravdu potřeba teprve v okamžiku kdy jsou data potřeba (například collapsed uzel je otevřen), data se načtou do paměti a zobrazí se příslušné komponenty v případě JTree se využívá rozhraní TreeWillExpandListener 10