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.

Die Klasse DateiBaum erweitert JFrame , stellt das GUI bereit und enthält die Main-Methode. Dem Konstruktor wird dort als Parameter der absoluten Pfad des Wurzelverzeichnisses übergeben. Im vorliegenden Fall ist dies das Heimatverzeichnis des Nutzers.
Innerhalb des Konstruktors wird der Pfad an die Methode createModel() weitergereicht. Sie erzeugt ein DefaultTreeModel , das den Inhalt des Baums verwaltet. Das Model selbst wird bei der Erzeugung des JTree an dessen Konstruktor übergeben und der JTree 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.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 extends JFrame {

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

    private String path;
    private int showType = SHOW_VISIBLE;
    private JTree tree;

    public DateiBaum(String path) {
        this.path = path;
        tree = new JTree(createModel(this.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);
        this.add(sPane, BorderLayout.CENTER);
        this.add(createButtPanel(), BorderLayout.SOUTH);

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.pack();
        this.setLocationRelativeTo(null);
        this.setTitle("Datei-Browser");
        this.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() {
        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 void setPath(String path) {
        this.path = path;
    }

    public static void main(String[] args) {
        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, nichtsichbar 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.