Dateibaum

Das Beispiel zeigt, wie ein Dateibaum geschrieben werden kann. Er wird, mit dem eigenen Home-Verzeichnis als Wurzel, auf einem JFrame dargestellt. Durch Radio-Buttons kann zwischen der Darstellung aller, nur versteckter oder nur sichtbarer Dateien gewählt werden.

Fenster mit Dateibaum

Die Klasse DateiBaum enthält main() und erzeugt in initGUI() einen JFrame mit dem GUI. Der dem Konstruktor übergebene absolute Pfad des Wurzelverzeichnisses wird als Parameter an initGUI() weitergereicht. Dort wird der Baum erzeugt, dessen Daten durch ein DefaultTreeModel verwaltet werden. Das Model selbst wird bei der Erzeugung des JTree an dessen Konstruktor übergeben und der JTree selbst auf ein JScrollPane gesetzt. Vorher wird der JTree noch bei einem TreeExpansionListener angemeldet. Er ist als anonyme Klasse realisiert, in der nur die Methode treeExpanded() überschrieben wird. Sie führt folgendes aus:

Wird ein Baumknoten angeklickt, so wird der Pfad zum Knoten als TreePath-Objekt und dessen letztes Element als FNode-Objekt ermittelt. Hierbei handelt es sich um eine Erweiterng eines DefaultMutableTreeNode, der zweiten im Beispiel deklarierten Klasse. Sie repräsentiert einen Baumknoten. Mehr dazu weiter unten.
Abschließend wird ein Panel mit Radio-Buttons unten auf den Frame gesetzt und desser Erscheinung auf die übliche Weise fertig konfiguriert.

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

public class DateiBaum {

    public final static int SHOW_ALL = 0;
    public final static int SHOW_HIDDEN = 1;
    public final static int SHOW_VISIBLE = -1;

    private int showType = SHOW_VISIBLE;

    public DateiBaum(String path) {
        initGUI(path);
    }
    
    private void initGUI(String path) {
        JTree tree = new JTree(createModel(path));
        tree.addTreeExpansionListener(new TreeExpansionListener() {

            public void treeExpanded(TreeExpansionEvent event) {
                TreePath path = event.getPath();
                FNode node = (FNode) path.getLastPathComponent();
                DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
                node.addFiles(showType);
                model.nodeStructureChanged(node);
            }

            public void treeCollapsed(TreeExpansionEvent event) {
            }
        });
        JScrollPane sPane = new JScrollPane(tree);
        JFrame frame = new JFrame("Datei-Browser");
        frame.add(sPane, BorderLayout.CENTER);
        frame.add(createButtPanel(tree, path), BorderLayout.SOUTH);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private DefaultTreeModel createModel(String path) {
        File root = new File(path);
        FNode rootNode = new FNode(root);
        rootNode.addFiles(showType);
        return new DefaultTreeModel(rootNode);
    }

    private JPanel createButtPanel(JTree tree, String path) {
        JPanel panel = new JPanel(new FlowLayout());
        JRadioButton allButt = new JRadioButton("Alle");
        allButt.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                showType = SHOW_ALL;
                tree.setModel(createModel(path));
            }
        });
        JRadioButton hiddenButt = new JRadioButton("Versteckt");
        hiddenButt.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                showType = SHOW_HIDDEN;
                tree.setModel(createModel(path));
            }
        });
        JRadioButton visibleButt = new JRadioButton("Sichtbar", true);
        visibleButt.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                showType = SHOW_VISIBLE;
                tree.setModel(createModel(path));
            }
        });
        ButtonGroup group = new ButtonGroup();
        group.add(allButt);
        group.add(hiddenButt);
        group.add(visibleButt);
        panel.add(allButt);
        panel.add(hiddenButt);
        panel.add(visibleButt);
        return panel;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new DateiBaum(System.getProperty("user.home")));
    }
}

class FNode extends DefaultMutableTreeNode {

    public FNode(File file) {
        setUserObject(file);
    }

    public File getFile() {
        return (File) getUserObject();
    }

    public boolean getAllowsChildren() {
        return getFile().isDirectory();
    }

    public boolean isLeaf() {
        return !getFile().isDirectory();
    }

    public String toString() {
        return getFile().getName();
    }

    public void addFiles(int showHidden) {
        File[] files = getFile().listFiles();
        for (File f : files) {
            if (showHidden == DateiBaum.SHOW_HIDDEN) {
                if (f.isHidden())
                    this.add(new FNode(f));
            } else if (showHidden == DateiBaum.SHOW_VISIBLE) {
                if (!f.isHidden())
                    this.add(new FNode(f));
            } else {
                this.add(new FNode(f));
            }
        }
    }

Die Klasse FNode erweitert DefaultMutableTreeNode, die ihrerseits einen Baumknoten mit 0 - n Kindknoten darstellt. Innerhalb eines Dateibaums wird hierdurch somit also eine Datei oder ein Verzeichnis repräsentiert. Der Konstruktor bekommt ein File-Objekt übergeben, das als sog. UserObject gesetzt wird. Als UserObject wird ein Object bezeichnet, das die durch den Nutzer spezifizierten Daten eines Baumknotens darstellt. In einem Dateibaum ist dies natürlich ein File-Objekt. Um es als Baumknoten zu spezifizieren, muss geklärt werden, ob es - als Verzeichnis - weitere File-Objekte enthalten kann oder nicht. Hierzu werden die beiden Methoden isLeaf() und getAllowsChildren() entsprechend überschrieben.

Eine weitere Methode muss erwähnt werden: addFiles() bekommt einen int-Parameter übergeben, mit dem entschieden werden kann, welcher Sichtbarkeitsstatus im Baum dargestellt werden soll. Hierzu wird zunächst der Inhalt des aktuellen UserObject als Array ermittelt. Es enthält die File-Objekte des Baumknotens, sofern dieser ein Verzeichnis ist. Das Array wird durchlaufen und jedes einzelne Element dem übergebenen Parameter gemäß überprüft und je nach Ergebnis (sichtbar, nicht sichbar oder beides) dem aktuellen UserObject hinzugefügt.
Die Methode wird an zwei Stellen aufgerufen: zum einen bei der initialen Generierung des TreeModel und zum zweiten in der Methode TreeExpansionListener#treeExpanded(), die jedesmal angesprochen wird, wenn ein Knoten des Baumes expandiert wird.

Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.