====== 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]]