====== Stromy ====== Podobně jako v [[open|první kapitole]] vytvoříme nový projekt, nazveme ho **Tree**. \\ Přidáme **JFrame** pojmenovaný **TreeWindow**. \\ ( A můžeme odstranit původní třídu //Tree//. ) Do //TreeWindow// přidáme z //palety// prvek //Tree//, vytvořenému prvku ponecháme identifikátor **jTree1**. Vytvoříme kořen stromu DefaultMutableTreeNode root = new DefaultMutableTreeNode ("first"); Pod kořenový prvek přidáme další prvek stromu DefaultMutableTreeNode node = new DefaultMutableTreeNode ("second"); root.add (node); DefaultMutableTreeNode root = new DefaultMutableTreeNode ("first"); Prvky stromu budou typu ** javax.swing.tree.DefaultMutableTreeNode **. \\ Na začátek programu přidáme ** import javax.swing.tree.*; ** \\ Na misto //DefaultMutableTreeNode// můžeme v //NetBeans// napsat velkými písmeny **DMTN** a stisknout **Ctrl+Mezera** Vytvoříme **"model"** (třídu dodávající data našemu stromu) DefaultTreeModel model = new DefaultTreeModel (root); jTree1.setModel (model); Tím máme jednodychý strom se dvěma prvky vytvořen package tree; import javax.swing.*; import javax.swing.tree.*; public class TreeWindow extends javax.swing.JFrame { DefaultMutableTreeNode root; DefaultTreeModel model; public TreeWindow() { initComponents(); root = new DefaultMutableTreeNode ("first"); DefaultMutableTreeNode node = new DefaultMutableTreeNode ("second"); root.add (node); model = new DefaultTreeModel (root); jTree1.setModel (model); } } [[https://gitlab.fjfi.cvut.cz/culikzde/java-priklady/-/blob/b06f9aa7/Tree/src/tree/TreeWindow.java|gitlab]] ===== Menu ===== Z **palety** ze skupiny **Swing Menus** přidáme do našeho okna **MenuBar**. \\ Na záložce **Navigator** v kontextovém menu vyvolaném pravou myší vybereme **change variable name** a přejmenujeme na **mainMenu** {{tree_navig.png}} Položky hlavního menu můžeme přejmenovat na **fileMenu** a **editMenu**. Pravou myší "klikneme" na menu **File**, z kontextov0ho menu vybereme **Add From Palette** a **Menu Item**. * Položku přejmenujeme na **quitMenuItem** * Nastavíme **text** na **Quit**. * Můžeme nastavit **mnemonic** na **Q** * **accelerator** nastavíme na **Ctrl+Q** Podobně do menu **Edit** přidáme také **Menu Item** * Položku přejmenujeme na **addMenuItem** * Nastavíme **text** na **Add Tree Item** * Můžeme nastavit **mnemonic** na **A** * **accelerator** nastavíme na **F7** Nakonec do **Edit** přidáme **Menu Item** * Položku přejmenujeme na **editMenuItem** * Nastavíme **text** na **Edit Tree Item** * Můžeme nastavit **mnemonic** na **E** * **accelerator** nastavíme na **F8** {{tree_menu.png}} V menu vybereme položku **Quit**. \\ Potom se v **Properties** přepneme na **Events**. \\ Vybereme řádku **actionPerformed**. \\ Do druhého sloupce napíšeme název funkce **quickClick** a stiskneme Enter Do vzniklé funkce jen dopíšeme ** dispose (); **, což uzavře naše okno a tím se ukončí náš program. \\ ( Můžeme se podívat, že //TreeWindow// má nastavenu vlastnost **defaultCloseOperation** na **EXIT_ON_CLOSE** ) private void quitClick(java.awt.event.ActionEvent evt) { dispose (); } Přidáme funkci **getNode**, kterou napíšeme celou včetně hlavičky (není to reakce na událost). \\ getNode zjistí právě vybraný prvek stromu (a nebo vrátí **null**) private DefaultMutableTreeNode getNode () { return (DefaultMutableTreeNode) jTree1.getLastSelectedPathComponent (); } ===== Vložení prvku do stromu ===== Na položku menu **Add Tree Item** připojíme funkci **addClick** (podobě jako jsme připojovali funkci k položce //Quit//) * **node** je právě vybraný prvek stromu * **item** bude nově vytvořený prvek stromu * nový prvek přidáme pod původní prvek **node.add (item);** * pokud je strom již zobrazen na obrazovce, funkce **model.nodesWereInserted** upozorní okno, že je třeba zobrazit nový prvek private void addClick(java.awt.event.ActionEvent evt) { DefaultMutableTreeNode node = getNode (); if (node != null) { DefaultMutableTreeNode item = new DefaultMutableTreeNode ("new item"); node.add (item); model.nodesWereInserted (node, new int [] {node.getIndex (item)}); } } ===== Editování prvku stromu ===== Na položku menu **Edit Tree Item** připojíme funkci **editClick** * **node** je právě vybraný prvek stromu * statická metoda **showInputDialog** ze třídy **JOptionPane** se uživatele zeptá na nové z třídy a uloží ho do proměnné **name** * Text vložíme do původního prvky stromu **node.setUserObject (name);** * funkce **model.nodeChanged** upozorní okno na změny private void editClick(java.awt.event.ActionEvent evt) { DefaultMutableTreeNode node = getNode (); if (node != null) { String name = JOptionPane.showInputDialog (this, "enter new name"); node.setUserObject (name); model.nodeChanged (node); } } ===== Reakce na pohyb ve stromu ===== V "design režimu" našeho okna vybereme strom **jTree1**, z kontextového menu vybereme **Events**, **Tree Selecttion** a **valueChanged** \\ Pokud uživatel "klikne" na prvek stromu, pomocí **setTitle** zobrazíme text ze stromu jako nadpis na horním okraji našeho okna private void jTree1ValueChanged(javax.swing.event.TreeSelectionEvent evt) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTree1.getLastSelectedPathComponent (); if (node != null) { setTitle (node.toString()); } } ===== Všechny přidané funkce ===== private void quitClick(java.awt.event.ActionEvent evt) { dispose (); } private DefaultMutableTreeNode getNode () { return (DefaultMutableTreeNode) jTree1.getLastSelectedPathComponent (); } private void addClick(java.awt.event.ActionEvent evt) { DefaultMutableTreeNode node = getNode (); if (node != null) { DefaultMutableTreeNode item = new DefaultMutableTreeNode ("new item"); node.add (item); model.nodesWereInserted (node, new int [] {node.getIndex (item)}); } } private void editClick(java.awt.event.ActionEvent evt) { DefaultMutableTreeNode node = getNode (); if (node != null) { String name = JOptionPane.showInputDialog (this, "enter new name"); node.setUserObject (name); model.nodeChanged (node); } } private void jTree1ValueChanged(javax.swing.event.TreeSelectionEvent evt) { DefaultMutableTreeNode node = getNode (); if (node != null) { setTitle (node.toString()); } } [[https://gitlab.fjfi.cvut.cz/culikzde/java-priklady/-/blob/e0625e59/Tree/src/tree/TreeWindow.java#L104|gitlab]] {{tree_run.png}} ===== Strom se jmény souborů ===== Vyuužijeme třídu **java.io.File** import java.io.*; Vytvoříme objekt typu **File**, konstruktoru předáme jako parametr dvě tečky označující nadřazený adresář Funkce ** f.getCanonicalFile () ** vrátí jiný objekt typu **File**, ve kterém bude uloženo skutečné jméno souboru getCanonicalFile může způsobit výjimku, v Javě ji musíme zachytit pomocí **try** **catch**. \\ Pokud se převod jména nepovede, //catch// nedělá v našem případě vůbec nic a v proměnné //f// zůstane odkaz na soubor s dvěmi tečkami /* root = new DefaultMutableTreeNode ("first"); DefaultMutableTreeNode node = new DefaultMutableTreeNode ("second"); root.add (node); */ File f = new File (".."); try { f = f.getCanonicalFile (); // prevedeme .. na opravdove jmeno adresare } catch (IOException ex) { } root = showFile (f); Funkce **showFile** vytvoří uzel ve stromu se jménem souboru (bez jména adresáře). \\ Pokud je soubor adresářem, funkce **listItems** vrátí pole objektů typu **File** představující soubory v daném adresáři. \\ Pro jednotlivé soubory ** for (File t : items) ** opět zavoláme **showFile** a vzniklé uzly přidáme do stromu. private DefaultMutableTreeNode showFile (File f) { DefaultMutableTreeNode node = new DefaultMutableTreeNode (f.getName()); if (f.isDirectory()) { File [] items = f.listFiles(); for (File t : items) { node.add (showFile (t)); } } return node; } {{tree_files.png}} [[https://gitlab.fjfi.cvut.cz/culikzde/java-priklady/-/blob/6491aff8/Tree/src/tree/TreeWindow.java|gitlab]] [[http://kmlinux.fjfi.cvut.cz/~culikzde/sos/Tree2020.zip|zip]]