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 <String> fileInfo = new Vector <String> ();

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 StringBuilderu, 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 <String []> lines = new Vector <String []> ();

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 <String []> lines = new Vector <String []> ();
            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 <String> fileInfo = new Vector <String> ();
 
    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 <String []> lines = new Vector <String []> ();
            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) { }
    }
}

gitlab zip

 
java/filetree.txt · Last modified: 2021/11/04 14:46 by 147.32.8.115
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki