====== Strom zobrazující adresáře se soubory ====== Vytvoříme nový projekt **FileTree**, přidáme okno **FileWindow** typu **JFrame** * do okna vložíme **JSplitPane**, rozdělující pohyblivou příčkou okno na dvě části * do pravé části vložíme další **JSplitPane** * **tree** typu **JTree** * **table** typu **JTable** * **tabs** typu **JTabbedPane** Výsledné okno je vidět obrázku na konci kapitoly ===== Třída MyData ===== Vytvoříme třídu **MyData** (na záložce //Project//, pravou myší //New//, //Java Class//) //MyData// bude obsahovat informace o jednotlivých adresářích * **path** úplné jméno adresáře * **name** krátké jméno obsahující jen poslední adresář * **ready** příznak, že ve stromu byly zobrazeny i podadresáře * funkci **toString** používanou jazykem Java při převodu objektu na řetězec znaků package filetree; class MyData { public String path; public String name; public boolean ready; public String toString () { return name; } } ===== Funkce showDirectories ===== * vytvoříme kořen stromu s textem "Files" * vytvoříme **treeModel**, kterému předáme kořenový prvek * zobrazovanému stromu předáme //treeModel// * pomocí funkce **File.listRoots ()** získáme seznam kořenových adresářů (C:, D:, ... nebo jen / na Linuxu) * pro každý adresář vytvoříme prvek stromu **node**, kterému předáme **data** obsahující cestu k adresáři * strom zobrazuje objekty s uživatelskými daty pomocí volání funkce **toString** * funkce **treeModel.insertNodeInto** informuje model a strom o vložení nového prvku * na konci funkce rozvineme kořenový prvek stromu, aby byly vidět jednotlivé kořenové adresáře private void showDirectories () { DefaultMutableTreeNode root = new DefaultMutableTreeNode ("Files"); treeModel = new DefaultTreeModel (root); tree.setModel (treeModel); File [] list = File.listRoots (); int cnt = 0; for (File f : list) { MyData data = new MyData (); data.name = f.getAbsolutePath (); data.path = f.getAbsolutePath(); DefaultMutableTreeNode node = new DefaultMutableTreeNode (data); treeModel.insertNodeInto (node, root, cnt); cnt ++; } tree.expandRow (0); } ===== Reakce na rozvinutí větve stromu ===== Adresářů je na disku příliš mnoho, budeme je ve stromu zobrazovat postupně, jak uživatel bude rozvíjet jednotlivé větve Při návrhu okna klikneme pravou myší na strom a vybereme **Events**, **TreeExpansion**, **treeExpanded** * do proměnné **node** uložíme odkaz na právě rozvíjený prvek stromu * **obj** bude obsahovat uživatelská data, která jsem prvku stromu předali jako parametr konstruktoru * otestujeme zda uživatelská data jsou typu **MyData** a uložíme do proměnné **data** * pokud podadresáře rozvíjeného adresáře dosud nebyly zobrazeny zavoláme funkci **addDirectory** Podobně zobrazíme i podadresáře podadresářů. \\ Pokud chceme u podadresářů, které mají opět podadresáře, vidět ikonu naznačující vnořené adresáře, \\ musíme ve stromu skladovat o jedno patro adresářů více než právě zobrazujeme. * **node.getChildCount ()** zjistí počet větví v právě rozvíjející se větvi * pomocí **node.getChildAt (i)** získáme odkaz na i-tou větev * funkce **getUserObject** poskytne uschovaná data * pokud v dané větvi nebyly zobrazeny adresáře, opět zavoláme **addDirectory** private void treeTreeExpanded(javax.swing.event.TreeExpansionEvent evt) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) evt.getPath ().getLastPathComponent (); if (node != null) { Object obj = node.getUserObject (); if (obj instanceof MyData) { MyData data = (MyData) node.getUserObject (); // System.out.println ("EXPANDED " + data.path); if (! data.ready) { addDirectory (node, data); } } int cnt = node.getChildCount (); for (int i = 0 ; i < cnt; i ++) { DefaultMutableTreeNode n = (DefaultMutableTreeNode) node.getChildAt (i); MyData d = (MyData) n.getUserObject (); if (! d.ready) { addDirectory (n, d); } } } } ===== Zobrazení podadresářů funkcí addDirectory ===== * Vytvoříme proměnnou **dir** typu **File**, konstruktoru zadáme cestou k adresáři * uzel stromu **topNode**, repreprezenující zadaný adresář je již ve stromu uložen * podadresáře, které chceme do stromu přidat, získáme funkcí **dir.listFiles ()** * seznam podadresářů setřídíme podle abecedy * pro jednotlivé podadresáře vytvoříme nové uzly stromu a umístíme je v rámci stromu private void addDirectory (DefaultMutableTreeNode topNode, MyData topData) { topData.ready = true; File dir = new File (topData.path); File [] list = dir.listFiles (); if (list != null) { Arrays.sort (list); int cnt = 0; for (File f : list) { if (f.isDirectory ()) { MyData data = new MyData (); data.name = f.getName (); data.path = f.getAbsolutePath(); DefaultMutableTreeNode node = new DefaultMutableTreeNode (data); treeModel.insertNodeInto (node, topNode, cnt); cnt ++; } } } } ===== Reakce na "kliknutí" ve stromu ===== Pokud "klikneme" na adresář, chceme v tabulce zobrazit seznam souborů Během návrhu okna klikneme pravou myší na strom a vybereme **Events**, **TreeSelection**, **valueChanged** Do proměnné **node** uložíme odkaz na uzel stromu. \\ Z uživatelských dat zjistíme cestu k odpovídajícímu adresáři. \\ Tabulku souborů zobrazíme funkcí **addFiles** private void treeValueChanged(javax.swing.event.TreeSelectionEvent evt) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); if (node != null) { Object obj = node.getUserObject (); if (obj instanceof MyData) { MyData data = (MyData) node.getUserObject (); // System.out.println ("SELECT " + data.path); addFiles (data.path); } } } ===== Funkce addFiles zobrazující tabulku souborů ===== Seznam jmen souborů právě zobrazených v tabulce budeme skladovat v proměnné **fileInfo** deklarované na úrovni třídy představující hlavní okno. \\ Proměnná bude typu **Vector** (šablonový typ obsahující dynamicky se zvětšující pole) obsahující položky typu //String//. private Vector fileInfo = new Vector (); Funkce //addFiles// * nejprve vymažeme původní obsah tabulky * vymažeme seznam //fileIno// * Vytvoříme proměnnou **dir** typu **File** představující adresář se soubory * Funkce **dir.listFiles ()** nám opět poskytne seznam souborů a adresářů * Vybereme jen soubory * Pro jednotlivé soubory přidáme cestu k soubory do seznamu //fileInfo// * Do pracovních proměnných si poznamenáme krátké jméno souboru, délku souboru a datum poslední změny * Vytvoříme pole objektů **line** obsahující vhodně naformátované informace * Pole přidáme jako další řádku do tabulky Object [] line = { name, formatNumber (size), fmt.format (date) }; tableModel.addRow (line); private void addFiles (String path) { tableModel.setRowCount (0); fileInfo.clear (); File dir = new File (path); File [] list = dir.listFiles (); SimpleDateFormat fmt = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss"); if (list != null) for (File f : list) { if (f.isFile ()) { fileInfo.add (f.getAbsolutePath()); String name = f.getName (); long size = f.length (); Date date = new Date (f.lastModified()); Object [] line = { name, formatNumber (size), fmt.format (date) }; tableModel.addRow (line); } } } ===== "Dvojité kliknutí" na soubor v tabulce ===== Při návrhu okna klikneme pravou myší na //tabulku// a vybereme **Events**, **Mouse**, **mouseClick** * pokud jde o druhé "kliknutí", poznamenáme si číslo řádky na kterou jsme kliknuli * pokud je vůbec nějaká řádka vybrána (číslo řádky není záporné) v seznamu //fileInfo// nalezneme cestu k souboru * podle přípony souboru zaloláme **showTextFile**, **showImage** nebo **showTable**, kreré přidají novou záložku zobrazující soubor private void tableMouseClicked(java.awt.event.MouseEvent evt) { if (evt.getClickCount () == 2) { int line = table.getSelectedRow (); if (line >= 0) { String path = fileInfo.elementAt (line); System.out.println ("DOUBLE CLICK " + path); if (path.endsWith (".java")) { showTextFile (path); } if (path.endsWith (".png") || path.endsWith (".bmp") || path.endsWith (".gif") || path.endsWith (".jpeg")) { showImage (path); } if (path.endsWith (".csv")) { showTable (path); } } } } ===== Zobrazení textového souboru ===== * připravíme si proměnnou typu **StringBuilder** pro efekivní načítání jednotlivých řádek ze souboru * vytvoříme **FileReader** se zadanou cestou k souboru * do proměnné **b** uložíme na **BufferedReader** napojený na //FileReader// * **b.ready ()** nás informuje zda lze číst ještě další data ze souboru * **b.readLine ()** přečte další řádku ze souboru * vytvoříme nové textové okéno **edit** typu **JTextArea** * okénku předáme text celého souboru, který jsme shormažďovali ve //StringBuilder//u, **edit.setText (t.toString());** * do **tabs** přidáme novou záložku, nadpis záložky bude krátké jméno souboru, záložka bude tvořena okénkem //edit// * nově přidanou záložku zobrazíme uživateli tabs.addTab (fileName (path), edit); tabs.setSelectedComponent (edit); Pokud během čtení souboru dojde k výjimce, nebudeme dělat nic //try { ... } catch (FileNotFoundException ex) { }// private void showTextFile (String path) { try { StringBuilder t = new StringBuilder (); FileReader r = new FileReader (path); BufferedReader b = new BufferedReader (r); while (b.ready ()) { t.append (b.readLine() + "\n"); } JTextArea edit = new JTextArea (); edit.setText (t.toString()); tabs.addTab (fileName (path), edit); tabs.setSelectedComponent (edit); } catch (FileNotFoundException ex) { } catch (IOException ex) { } } ===== Obrázek ===== * **ImageIO.read** načte obrázek ze souboru * na základě načtených dat vytvoříme objekt typu **Icon** * vytvoříme **JLabel** se zadanou ikonku * přídáme záložku na pravou stranu okna private void showImage (String path) { try { BufferedImage img = ImageIO.read (new File (path)); Icon icon = new ImageIcon (img); JLabel label = new JLabel (); label.setIcon (icon); tabs.addTab (fileName (path), label); tabs.setSelectedComponent (label); } catch (IOException ex) { } } ===== Tabulka hodnot ===== Soubory s příponou **".csv"** zobrazíme pomocí **JTable** * Jednotlivé buňky v tabulce budeme skladovat jako typ **String** * Jednu řádku tabulky budeme ukládat do pole řetězců (**String []**) * Celou tabulku uložíme do proměnné **lines**, dynamického pole obsahující jednoltivé řádky Vector lines = new Vector (); Dříve než vytvoříme model tabulky, potřebujeme znát počet sloupců * Jednotlivé řádky přečteme ze souboru stejně jako v případě textového souboru * Funkce **s.split (",")** rozdělí řádku na jednotlivé hodnoty a vznikne pole řetězců * Do **cnt** si poznamenáme počet hodnot v dané řádce * V **columns** budeme skladovat počet hodnot na nejdelší řádce * Pole hodnot přidáme do "vektoru" **lines** String s = b.readLine (); String [] data = s.split (","); int cnt = data.length; if (cnt > columns) columns = cnt; lines.add (data); * vytvoříme novou tabulku typu **JTable** * v tabulce budeme zobrazovat čáry kolem jednotlivých políček * do proměnné **m** uložíme odkaz na model skladující data nové tabulky * nastavíme počet sloupců tabulky * z **lines** vyzvedneme jednotlivá pole řetězců představující jednotlivé řádky * pole řetězců přidáme do tabulky JTable t = new JTable (); t.setShowGrid (true); DefaultTableModel m = (DefaultTableModel) t.getModel (); m.setColumnCount (columns); for (String [ ] line : lines) m.addRow (line); private void showTable (String path) { try { FileReader r = new FileReader (path); BufferedReader b = new BufferedReader (r); Vector lines = new Vector (); int columns = 0; while (b.ready ()) { String s = b.readLine (); String [] data = s.split (","); int cnt = data.length; if (cnt > columns) columns = cnt; lines.add (data); } JTable t = new JTable (); t.setShowGrid (true); DefaultTableModel m = (DefaultTableModel) t.getModel (); m.setColumnCount (columns); for (String [ ] line : lines) m.addRow (line); tabs.addTab (fileName (path), t); tabs.setSelectedComponent (t); } catch (IOException ex) { } } ===== Celý program ==== package filetree; import java.awt.image.*; import java.io.*; import java.text.*; import java.time.format.*; import java.util.*; import javax.imageio.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.table.*; import javax.swing.tree.*; public class FileWindow extends javax.swing.JFrame { private DefaultTreeModel treeModel; private DefaultTableModel tableModel; private Vector fileInfo = new Vector (); public FileWindow() { initComponents(); tableModel = (DefaultTableModel) table.getModel (); showDirectories (); } private void showDirectories () { DefaultMutableTreeNode root = new DefaultMutableTreeNode ("Files"); treeModel = new DefaultTreeModel (root); tree.setModel (treeModel); File [] list = File.listRoots (); int cnt = 0; for (File f : list) { if (f.isDirectory ()) { MyData data = new MyData (); data.name = f.getAbsolutePath (); data.path = f.getAbsolutePath(); DefaultMutableTreeNode node = new DefaultMutableTreeNode (data); treeModel.insertNodeInto (node, root, cnt); cnt ++; } } tree.expandRow (0); } private void treeValueChanged(javax.swing.event.TreeSelectionEvent evt) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); if (node != null) { Object obj = node.getUserObject (); if (obj instanceof MyData) { MyData data = (MyData) node.getUserObject (); // System.out.println ("SELECT " + data.path); addFiles (data.path); } } } private void treeTreeExpanded(javax.swing.event.TreeExpansionEvent evt) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) evt.getPath ().getLastPathComponent (); if (node != null) { Object obj = node.getUserObject (); if (obj instanceof MyData) { MyData data = (MyData) node.getUserObject (); // System.out.println ("EXPANDED " + data.path); if (! data.ready) { addDirectory (node, data); } } int cnt = node.getChildCount (); for (int i = 0 ; i < cnt; i ++) { DefaultMutableTreeNode n = (DefaultMutableTreeNode) node.getChildAt (i); MyData d = (MyData) n.getUserObject (); if (! d.ready) { // System.out.println ("ADD " + d.path); addDirectory (n, d); } } } } private void addDirectory (DefaultMutableTreeNode topNode, MyData topData) { topData.ready = true; File dir = new File (topData.path); File [] list = dir.listFiles (); if (list != null) { Arrays.sort (list); int cnt = 0; for (File f : list) { if (f.isDirectory ()) { MyData data = new MyData (); data.name = f.getName (); data.path = f.getAbsolutePath(); DefaultMutableTreeNode node = new DefaultMutableTreeNode (data); treeModel.insertNodeInto(node, topNode, cnt); cnt ++; } } } } private String formatNumber (long number) { String s = "" + number; int len = s.length (); String result = ""; int cnt = 0; for (int i = len-1; i >= 0; i--) { result = s.charAt (i) + result; cnt ++; if (cnt % 4 == 3) { result = ' ' + result; cnt ++; } } while (cnt <= 12) { result = ' ' + result; cnt ++; } return result; } private void addFiles (String path) { tableModel.setRowCount (0); fileInfo.clear (); File dir = new File (path); File [] list = dir.listFiles (); SimpleDateFormat fmt = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss"); if (list != null) for (File f : list) { if (f.isFile ()) { fileInfo.add (f.getAbsolutePath()); String name = f.getName (); long size = f.length (); Date date = new Date (f.lastModified()); Object [] line = { name, formatNumber (size), fmt.format (date) }; tableModel.addRow (line); } } } private void tableMouseClicked(java.awt.event.MouseEvent evt) { if (evt.getClickCount () == 2) { int line = table.getSelectedRow (); if (line >= 0) { String path = fileInfo.elementAt (line); System.out.println ("DOUBLE CLICK " + path); if (path.endsWith (".java")) { showTextFile (path); } if (path.endsWith (".png") || path.endsWith (".bmp") || path.endsWith (".gif") || path.endsWith (".jpeg")) { showImage (path); } if (path.endsWith (".csv")) { showTable (path); } } } } private String fileName (String path) { File f = new File (path); return f.getName (); } private void showTextFile (String path) { try { StringBuilder t = new StringBuilder (); FileReader r = new FileReader (path); BufferedReader b = new BufferedReader (r); while (b.ready ()) { t.append (b.readLine() + "\n"); } JTextArea edit = new JTextArea (); edit.setText (t.toString()); tabs.addTab (fileName (path), edit); tabs.setSelectedComponent (edit); } catch (FileNotFoundException ex) { } catch (IOException ex) { } } private void showImage (String path) { try { BufferedImage img = ImageIO.read (new File (path)); Icon icon = new ImageIcon (img); JLabel label = new JLabel (); label.setIcon (icon); tabs.addTab (fileName (path), label); tabs.setSelectedComponent (label); } catch (IOException ex) { } } private void showTable (String path) { try { FileReader r = new FileReader (path); BufferedReader b = new BufferedReader (r); Vector lines = new Vector (); int columns = 0; while (b.ready ()) { String s = b.readLine (); String [] data = s.split (","); int cnt = data.length; if (cnt > columns) columns = cnt; lines.add (data); } JTable t = new JTable (); t.setShowGrid (true); DefaultTableModel m = (DefaultTableModel) t.getModel (); m.setColumnCount (columns); for (String [ ] line : lines) m.addRow (line); tabs.addTab (fileName (path), t); tabs.setSelectedComponent (t); } catch (IOException ex) { } } } {{filetree.png??1024}} [[https://gitlab.fjfi.cvut.cz/culikzde/java-priklady/-/blob/master/FileTree/src/filetree/FileWindow.java|gitlab]] [[http://kmlinux.fjfi.cvut.cz/~culikzde/sos/2020/FileTree2020.zip|zip]]