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