Como apresentar unidades de disco, diretórios e arquivos em um JTree?

2015/10/09

Este exemplo mostra uma forma de implementar um TreeNode para que a JTree possa apresentar as unidades de disco, diretórios e arquivos de seu sistema operacional.

import java.awt.BorderLayout;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.tree.TreeNode;

public class Exemplo {

    public static void main(String[] args) {
        try {
            // Gosto de deixar as telas com o Look & Feel nativo do sistema operacional
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

            // Primeiro criamos um TreeNode que sabe renderizar as unidades, diretórios e arquivos do sistema
            TreeNode diretorioRaiz = new NodoArquivo();
            // Em seguida criamos um JTree passando este TreeNode como parâmetro
            JTree tree = new JTree(diretorioRaiz);

            // Agora é só colocar o JTree em uma tela e apresentar
            JScrollPane scrollPane = new JScrollPane(tree);
            JFrame janela = new JFrame("Explorador de Arquivos");
            janela.add(BorderLayout.CENTER, scrollPane);
            janela.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            janela.setSize(320, 480);
            janela.setLocationRelativeTo(null);
            janela.setVisible(true);
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

Abaixo está a implementação do TreeNode:

import java.io.File;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Vector;

import javax.swing.tree.TreeNode;

public class NodoArquivo implements TreeNode {

    protected static final String RAIZ = "Raíz do Sistema";

    // Comparator utilizado para listar os objetos File em ordem alfabética
    private static final Comparator<? super NodoArquivo> ORDEM_ALFABETICA = new Comparator<NodoArquivo>() {
        @Override
        public int compare(NodoArquivo n1, NodoArquivo n2) {
            File a1 = n1.arquivo;
            File a2 = n2.arquivo;
            String caminho1 = a1 == null ? RAIZ : a1.getPath().toLowerCase();
            String caminho2 = a2 == null ? RAIZ : a2.getPath().toLowerCase();
            return caminho1.compareTo(caminho2);
        }
    };

    // Comparator utilizado para listar os objetos File de forma que os diretórios apareçam primeiro
    private static final Comparator<? super NodoArquivo> DIRETORIOS_PRIMEIRO = new Comparator<NodoArquivo>() {
        @Override
        public int compare(NodoArquivo n1, NodoArquivo n2) {
            if (isDirectory(n1.arquivo)) {
                if (isDirectory(n2.arquivo)) {
                    return 0;
                }
                return -1;
            }
            if (isDirectory(n2.arquivo)) {
                return 1;
            }
            return 0;
        }
    };

    private static boolean isDirectory(File arquivo) {
        if (arquivo == null || arquivo.isDirectory()) {
            return true;
        }
        for (File raiz : File.listRoots()) {
            if (arquivo.getPath().equals(raiz.getPath())) {
                return true;
            }
        }
        return false;
    }

    private final NodoArquivo pai;

    private final File arquivo;

    private Vector<NodoArquivo> filhos;

    public NodoArquivo() {
        this(null, null);
    }

    private NodoArquivo(NodoArquivo pai, File arquivo) {
        this.pai = pai;
        this.arquivo = arquivo == null ? null : arquivo.getAbsoluteFile();
    }

    @Override
    public Enumeration<NodoArquivo> children() {
        return getNodosFilhos().elements();
    }

    @Override
    public boolean getAllowsChildren() {
        return isDirectory(arquivo);
    }

    @Override
    public TreeNode getChildAt(int childIndex) {
        return getNodosFilhos().get(childIndex);
    }

    @Override
    public int getChildCount() {
        return getNodosFilhos().size();
    }

    @Override
    public int getIndex(TreeNode node) {
        return getNodosFilhos().indexOf(node);
    }

    @Override
    public TreeNode getParent() {
        return pai;
    }

    @Override
    public boolean isLeaf() {
        return arquivo == null ? false : arquivo.isFile();
    }

    @Override
    public String toString() {
        if (arquivo == null) {
            return RAIZ;
        }
        if (arquivo.getParentFile() == null) {
            return arquivo.toString();
        }
        return arquivo.getName();
    }

    private Vector<NodoArquivo> getNodosFilhos() {
        if (filhos == null) {
            filhos = new Vector<>();
            File[] arquivos = arquivo == null ? File.listRoots() : arquivo.listFiles();
            if (arquivos != null) {
                for (File arquivo : arquivos) {
                    filhos.add(new NodoArquivo(this, arquivo));
                }
                Collections.sort(filhos, ORDEM_ALFABETICA);
                Collections.sort(filhos, DIRETORIOS_PRIMEIRO);
            }

        }
        return filhos;
    }
}

É isso, espero que possa ser útil.