解説

  • JTreeとJListで作るエクスプローラ風のサンプル-
    • JTreeにディレクトリ構造を表示
    • JListにJTreeで選択したディレクトリの内容を表示
    • JListのディレクトリをダブルクリック、エンターでディレクトリの中を表示
    • JListのファイルをダブルクリック、エンターで関連付け実行

参考
 FileSystemViewを使ってディレクトリ構造をJTreeに表示する - Java Swing Tips
 http://terai.xrea.jp/Swing/DirectoryTree.html

参考というかJTreeの部分はちょこちょこ改造したけど、殆どそのままJListを追加した形です

ソース ExplorerLikeSample.java

/*
 * JTreeとJListで作るエクスプローラ風のサンプル
 *  ・JTreeにディレクトリ構造を表示
 *  ・JListにJTreeで選択したディレクトリの内容を表示
 *  ・JListのディレクトリをダブルクリック、エンターでディレクトリの中を表示
 *  ・JListのファイルをダブルクリック、エンターで関連付け実行
 * 参考
 *  FileSystemViewを使ってディレクトリ構造をJTreeに表示する - Java Swing Tips
 *  http://terai.xrea.jp/Swing/DirectoryTree.html
 *  参考というかJTreeの部分はちょこちょこ改造したけど、殆どそのままJListを追加した形です
 */
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
 
import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.filechooser.FileSystemView;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
 
import sun.awt.shell.ShellFolder;
 
public class ExplorerLikeSample extends JPanel {
	DefaultListModel listModel;
	DefaultTreeModel treeModel;
	JTree tree;
	JList jList;
 
	public ExplorerLikeSample() {
		super(new BorderLayout());
		FileSystemView fileSystemView = FileSystemView.getFileSystemView();
		DefaultMutableTreeNode root = new DefaultMutableTreeNode();
		treeModel = new DefaultTreeModel(root);
		for (File fileSystemRoot : fileSystemView.getRoots()) {
			DefaultMutableTreeNode node = new DefaultMutableTreeNode(
					fileSystemRoot);
			root.add(node);
			for (File file : fileSystemView.getFiles(fileSystemRoot, true)) {
				if (file.isDirectory()) {
					node.add(new DefaultMutableTreeNode(file));
				}
			}
		}
 
		// 初期化の追加部分
		tree = new JTree(treeModel);
		tree.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
		tree.setRootVisible(false);
		tree.addTreeSelectionListener(new FolderSelectionListener(
				fileSystemView));
		tree.setCellRenderer(new FileTreeCellRenderer(tree.getCellRenderer(),
				fileSystemView));
		tree.expandRow(0);
 
		JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
		sp.setDividerSize(1);
		sp.add(new JScrollPane(tree), 0);
 
		listModel = new DefaultListModel();
		JList list = new JList(listModel);
		list.setFixedCellHeight(84);
		list.setFixedCellWidth(84);
		list.setCellRenderer(new FileListCellRenderer(fileSystemView));
		list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
		list.setVisibleRowCount(0);
		list.addMouseListener(new ListMouseListener());
		list.addKeyListener(new ListKeyListener());
		jList = list;
		sp.add(new JScrollPane(list), 1);
		add(sp);
		// 初期化の追加部分ここまで
 
		setPreferredSize(new Dimension(400, 240));
	}
 
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			@Override
			public void run() {
				createAndShowGUI();
			}
		});
	}
 
	public static void createAndShowGUI() {
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception e) {
			e.printStackTrace();
		}
		JFrame frame = new JFrame("Swingエクスプローラ風サンプル(JTree, JList)");
		frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		frame.getContentPane().add(new ExplorerLikeSample());
		frame.pack();
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
	}
 
	class FolderSelectionListener implements TreeSelectionListener {
		private final FileSystemView fileSystemView;
 
		public FolderSelectionListener(FileSystemView fileSystemView) {
			this.fileSystemView = fileSystemView;
		}
 
		@Override
		public void valueChanged(TreeSelectionEvent e) {
			JTree tree = (JTree) e.getSource();
			DefaultMutableTreeNode node = (DefaultMutableTreeNode) e.getPath()
					.getLastPathComponent();
 
			DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
 
			File parent = (File) node.getUserObject();
			if (parent == null || !parent.isDirectory())
				return;
 
			SwingWorker<String, File> worker = new SwingWorker<String, File>() {
				File parent;
				DefaultMutableTreeNode node;
				DefaultTreeModel model;
 
				SwingWorker<String, File> setParam(File parent,
						DefaultMutableTreeNode node, DefaultTreeModel model) {
					this.parent = parent;
					this.node = node;
					this.model = model;
					return this;
				}
 
				@Override
				public String doInBackground() {
					File[] children = fileSystemView.getFiles(parent, true);
					publish(children);
					return "done";
				}
 
				@Override
				protected void process(List<File> children) {
					HashMap<File, File> map = new HashMap<File, File>();
					listModel.removeAllElements();
 
					boolean isLeaf = node.isLeaf();
					if (!isLeaf) {
						DefaultMutableTreeNode n = (DefaultMutableTreeNode) node
								.getFirstChild();
						while (n != null) {
							File f = (File) n.getUserObject();
							map.put(f, f);
							n = n.getNextNode();
						}
					}
 
					for (File child : children) {
						if (child.isDirectory()) {
							if (isLeaf) {
								node.add(new DefaultMutableTreeNode(child));
							} else {
								if (!map.containsKey(child)) {
									node.add(new DefaultMutableTreeNode(child));
								}
							}
						}
						// list更新
						listModel.addElement(child);
					}
					model.nodeStructureChanged(node);
				}
			}.setParam(parent, node, model);
 
			worker.execute();
		}
	}
 
	class FileTreeCellRenderer extends DefaultTreeCellRenderer {
		private final TreeCellRenderer renderer;
		private final FileSystemView fileSystemView;
 
		public FileTreeCellRenderer(TreeCellRenderer renderer,
				FileSystemView fileSystemView) {
			this.renderer = renderer;
			this.fileSystemView = fileSystemView;
		}
 
		public Component getTreeCellRendererComponent(JTree tree, Object value,
				boolean isSelected, boolean expanded, boolean leaf, int row,
				boolean hasFocus) {
			JLabel c = (JLabel) renderer.getTreeCellRendererComponent(tree,
					value, isSelected, expanded, leaf, row, hasFocus);
			if (isSelected) {
				c.setOpaque(false);
				c.setForeground(getTextSelectionColor());
			} else {
				c.setOpaque(true);
				c.setForeground(getTextNonSelectionColor());
				c.setBackground(getBackgroundNonSelectionColor());
			}
			if (value instanceof DefaultMutableTreeNode) {
				DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
				Object o = node.getUserObject();
				if (o instanceof File) {
					File file = (File) o;
					c.setIcon(fileSystemView.getSystemIcon(file));
					c.setText(fileSystemView.getSystemDisplayName(file));
					c.setToolTipText(file.getPath());
				}
			}
			return c;
		}
	}
 
	// 以降が追加部分
	/**
	 * JList用のキーリスナー
	 */
	class ListKeyListener extends KeyAdapter {
		@Override
		public void keyReleased(KeyEvent e) {
			super.keyTyped(e);
			if (e.getKeyCode() == KeyEvent.VK_ENTER) {
				listAction();
			} else if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
				listBack();
			}
		}
	}
 
	/**
	 * JList用のマウスリスナー
	 */
	class ListMouseListener extends MouseAdapter {
		@Override
		public void mouseClicked(MouseEvent e) {
			super.mouseClicked(e);
			if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
				listAction(e.getPoint());
			}
		}
	}
 
	/**
	 * JListの選択アイテムのアクション
	 */
	void listAction() {
		listAction(jList.getSelectedIndex());
	}
 
	/**
	 * JListの指定座標のアクション
	 */
	void listAction(Point point) {
		// カーソル下のアイテム選択
		int index = jList.locationToIndex(point);
		if (!jList.getCellBounds(index, index).contains(point)) {
			index = -1;
		}
		if (index >= 0) {
			listAction(index);
		}
 
	}
 
	/**
	 * JList用の指定インデックスのアクション
	 */
	private void listAction(int index) {
		File f = (File) listModel.get(index);
		if (f.isDirectory()) {
			listActionDirectry(f);
		} else {
			listActionFile(f);
		}
	}
 
	/**
	 * JList用のファイルアクション
	 */
	private void listActionFile(File f) {
		if (!Desktop.isDesktopSupported()) {
			return;
		}
		try {
			Desktop.getDesktop().open(f);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
 
	/**
	 * JList用のディレクトリアクション
	 */
	private void listActionDirectry(File f) {
		TreePath path = tree.getSelectionPath();
		DefaultMutableTreeNode n = (DefaultMutableTreeNode) path
				.getLastPathComponent();
		File tf = (File) n.getUserObject();
		File pf = f.getParentFile();
		if (tf.equals(pf)) {
			for (int i = 0; i < n.getChildCount(); i++) {
				DefaultMutableTreeNode c = (DefaultMutableTreeNode) n
						.getChildAt(i);
				File cf = (File) c.getUserObject();
				if (cf.equals(f)) {
					TreePath newPath = path.pathByAddingChild(c);
					tree.setSelectionPath(newPath);
				}
			}
		}
	}
 
	/**
	 * 戻るアクション
	 */
	private void listBack() {
		TreePath path = tree.getSelectionPath().getParentPath();
		if (path != null && path.getPathCount() != 0) {
			tree.setSelectionPath(path);
		}
	}
 
	/**
	 * JList用のセルセンダラー
	 */
	class FileListCellRenderer extends DefaultListCellRenderer {
		FileSystemView fs = FileSystemView.getFileSystemView();
 
		public FileListCellRenderer(FileSystemView fileSystemView) {
			this.fs = fileSystemView;
 
			// テキストを下に表示する
			setVerticalTextPosition(BOTTOM);
			// テキスト中央揃え
			setHorizontalTextPosition(CENTER);
			// アイコン中央揃え
			setVerticalAlignment(CENTER);
			setHorizontalAlignment(CENTER);
		}
 
		public Component getListCellRendererComponent(JList list, Object value,
				int index, boolean isSelected, boolean cellHasFocus) {
			super.getListCellRendererComponent(list, value, index, isSelected,
					cellHasFocus);
 
			if (value instanceof File) {
				File f = (File) value;
				setText(fs.getSystemDisplayName(f));
				Icon icon = null;
				try {
					Image img = ShellFolder.getShellFolder(f).getIcon(true);
					if (img != null) {
						icon = new ImageIcon(img);
					} else {
						icon = UIManager
								.getIcon(f.isDirectory() ? "FileView.directoryIcon"
										: "FileView.fileIcon");
					}
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				}
 
				setIcon(icon);
			}
			return this;
		}
	}
}
 

ShellFolderのエラー


eclipseから見ると赤いマークが出ててイラッとしますが、このままで実行できました。不思議

参考
 FileのSystemIconを取得する - Java Swing Tips
 http://terai.xrea.jp/Swing/SystemIcon.html

今後のリリースで削除される可能性がある?もしかしたらOpenJDKには入ってなかったりするのかな?
最終更新:2012年10月07日 16:31