I am trying to show only directories in JTree but my below code is showing is directories and files both .can anyone please help me to show only directories.
//Class1
public class FileBrowser implements Runnable {
private DefaultMutableTreeNode root;
private DefaultTreeModel treeModel;
private JTree tree;
#Override
public void run() {
JFrame frame = new JFrame("File Browser");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
File fileRoot = new File("C:\\JDeveloper\\Testing");
root = new DefaultMutableTreeNode(new FileNodes(fileRoot));
treeModel = new DefaultTreeModel(root);
tree = new JTree(treeModel);
tree.setCellRenderer(new DefaultTreeCellRenderer() {
private Icon loadIcon = UIManager.getIcon("OptionPane.errorIcon");
private Icon saveIcon = UIManager.getIcon("OptionPane.informationIcon");
#Override
public Component getTreeCellRendererComponent(JTree tree,
Object value,
boolean bSelected,
boolean bExpanded,
boolean bLeaf,
int iRow,
boolean bHasFocus ) {
Component c = super.getTreeCellRendererComponent(tree, value,
bSelected, bExpanded, bLeaf, iRow, bHasFocus);
return c;
}
});
tree.setShowsRootHandles(true);
JScrollPane scrollPane = new JScrollPane(tree);
frame.add(scrollPane);
frame.setLocationByPlatform(true);
frame.setSize(640, 480);
frame.setVisible(true);
CreateChildNode ccn = new CreateChildNode(fileRoot, root);
new Thread(ccn).start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new FileBrowser());
}
}
//Class 2
class CreateChildNode implements Runnable {
private DefaultMutableTreeNode root;
private File fileRoot;
public CreateChildNode(File fileRoot, DefaultMutableTreeNode root) {
this.fileRoot = fileRoot;
this.root = root;
}
#Override
public void run() {
createChildren(fileRoot, root);
}
private void createChildren(File fileRoot,
DefaultMutableTreeNode root) {
File[] files = fileRoot.listFiles();
for (File child : files) {
System.out.println("Path :" +child.getName());
DefaultMutableTreeNode childNode =
new DefaultMutableTreeNode(new FileNodes(child));
System.out.println("Child Node :" +childNode);
System.out.println("File :" +child.getAbsoluteFile());
root.add(childNode);
if (child.isDirectory() ) {
createChildren(child, childNode);
}
}
}
}
class FileNodes {
private File file;
public FileNodes(File file) {
this.file = file;
}
public File getFile() {
return file;
}
#Override
public String toString() {
String name = file.getName();
if (name.equals("")) {
return file.getAbsolutePath();
} else {
return name;
}
}
}
Simply check for a directory before add to the tree
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import java.awt.*;
import java.io.File;
/**
* Created by keshan on 7/26/2016.
*/
public class FileBrowser implements Runnable {
private DefaultMutableTreeNode root;
private DefaultTreeModel treeModel;
private JTree tree;
#Override
public void run() {
JFrame frame = new JFrame("File Browser");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
File fileRoot = new File("C:");
root = new DefaultMutableTreeNode(new FileNodes(fileRoot));
treeModel = new DefaultTreeModel(root);
tree = new JTree(treeModel);
tree.setCellRenderer(new DefaultTreeCellRenderer() {
private Icon loadIcon = UIManager.getIcon("OptionPane.errorIcon");
private Icon saveIcon = UIManager.getIcon("OptionPane.informationIcon");
#Override
public Component getTreeCellRendererComponent( JTree tree,
Object value,
boolean bSelected,
boolean bExpanded,
boolean bLeaf,
int iRow,
boolean bHasFocus ) {
Component c = super.getTreeCellRendererComponent(tree, value,
bSelected, bExpanded, false, iRow, bHasFocus);
return c;
}
});
tree.setShowsRootHandles(true);
JScrollPane scrollPane = new JScrollPane(tree);
frame.add(scrollPane);
frame.setLocationByPlatform(true);
frame.setSize(640, 480);
frame.setVisible(true);
CreateChildNode ccn = new CreateChildNode(fileRoot, root);
new Thread(ccn).start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new FileBrowser());
}
}
class CreateChildNode implements Runnable {
private DefaultMutableTreeNode root;
private File fileRoot;
public CreateChildNode(File fileRoot, DefaultMutableTreeNode root) {
this.fileRoot = fileRoot;
this.root = root;
}
#Override
public void run() {
createChildren(fileRoot, root);
}
private void createChildren(File fileRoot, DefaultMutableTreeNode root)
{
File[] files = fileRoot.listFiles();
if ( files != null )
{
for( File child : files )
{
DefaultMutableTreeNode childNode = new DefaultMutableTreeNode( new FileNodes( child ) );
if( child.isDirectory() )
{
root.add( childNode );
createChildren( child, childNode );
}
}
}
}
}
class FileNodes {
private File file;
public FileNodes(File file) {
this.file = file;
}
public File getFile() {
return file;
}
#Override
public String toString() {
String name = file.getName();
if (name.equals("")) {
return file.getAbsolutePath();
} else {
return name;
}
}
}
You can do this in java as below
File file=new File("PATH_TO_FILE");
String directories[]=file.list(new FilenameFilter()
{
public boolean accept(File yourFile, String name) {
return new File(yourFile, name).isDirectory();
}
}
Related
This may be a bit confusing to explain but I will try my best. I have a class called FileBrowser and there is a line which is String hello=fileNode.getFile that takes the clicked file node from the Jtree and saves it to the variable hello. Full class is below.
FileBrowser.java
import java.awt.BorderLayout;
import java.io.File;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import org.apache.commons.io.FileUtils;
public class FileBrowser extends JPanel {
public DefaultMutableTreeNode root;
public DefaultTreeModel treeModel;
public JTree tree;
public FileBrowser() {
//JFrame frame = new JFrame("File Browser");
//frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
File fileRoot = new File("C://");
root = new DefaultMutableTreeNode(new FileNode(fileRoot));
treeModel = new DefaultTreeModel(root);
tree = new JTree(treeModel);
tree.setShowsRootHandles(true);
JScrollPane scrollPane = new JScrollPane(tree);
tree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent event) {
/* new */
DefaultMutableTreeNode dmtn = (DefaultMutableTreeNode)
tree.getLastSelectedPathComponent();
FileNode fileNode = (FileNode)dmtn.getUserObject();
File file = fileNode.getFile();
//THIS THE STRING I WOULD LIKE TO TRANSFER TO VIEWER_NAVIGATOR
String hello=file.toString();
call(hello,dmtn);
}
});
// frame.add(scrollPane);
//frame.setLocationByPlatform(true);
//frame.setSize(640, 480);
//frame.setVisible(true);
CreateChildNodes ccn =
new CreateChildNodes(fileRoot, root);
new Thread(ccn).start();
}
private void call(String file, DefaultMutableTreeNode dmtn) {
System.out.println("Exporting file and converting to HTML");
String[] arguments = new String[] {file, dmtn+".html", "HTML"};
OITSample.func(arguments);
}
public class CreateChildNodes implements Runnable {
private DefaultMutableTreeNode root;
private File fileRoot;
public CreateChildNodes(File fileRoot,
DefaultMutableTreeNode root) {
this.fileRoot = fileRoot;
this.root = root;
}
public void run() {
createChildren(fileRoot, root);
}
private void createChildren(File fileRoot,
DefaultMutableTreeNode node) {
File[] files = fileRoot.listFiles();
if (files == null) return;
for (File file : files) {
DefaultMutableTreeNode childNode =
new DefaultMutableTreeNode(new FileNode(file));
node.add(childNode);
if (file.isDirectory()) {
createChildren(file, childNode);
}}}}
public class FileNode {
private File file;
public FileNode(File file) {
this.file = file;
}
public File getFile() {
return file;
}
#Override
public String toString() {
String name = file.getName();
if (name.equals("")) {
return file.getAbsolutePath();
} else {
return name;
}}}}
I would like to take the String variable,hello, and when a file node is clicked, the variable gets sent to the Viewer_Navigator class below, to the area which takes a file at the editorpane. This is area specifically:
File file = new File("the string hello from the other class should go in here");
Viewer_Navigator.java
public class Viewer_Navigator {
private JFrame frame;
public static void main(String[] args) {
String defStartParams = "AdminStart.xml";
String adminParams = parseXML(defStartParams);
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Viewer_Navigator window = new Viewer_Navigator();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private static String parseXML(String defStartParams) {
// We're cheating for now
String params = "sb_ContName='com.staorbase.service.SB_AdminSvc'";
params += ";";
return params;
}
/**
* Create the application.
*/
public Viewer_Navigator() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
}
});
frame.setBounds(100, 100, 840, 545);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null); //put the jframe on center of the screen -added
JToolBar toolBar = new JToolBar();
frame.getContentPane().add(toolBar, BorderLayout.NORTH);
final JSplitPane splitPane = new JSplitPane();
splitPane.setDividerLocation(0.8);
splitPane.setResizeWeight(0.3);
frame.getContentPane().add(splitPane, BorderLayout.CENTER);
FileBrowser testing=new FileBrowser();
final JEditorPane editorpane= new JEditorPane();
final JScrollPane editorScrollPane = new JScrollPane(editorpane);
editorScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
final JPanel panel2 = new JPanel(new BorderLayout());
panel2.add(editorScrollPane);
File file = new File("the string 'hello' from the other class should go in here");
try {
editorpane.setPage(file.toURI().toURL());
} catch (MalformedURLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
JScrollPane jScrollPane=new JScrollPane();
jScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
jScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
jScrollPane.setViewportBorder(new LineBorder(Color.BLUE));
jScrollPane.getViewport().add(testing.tree);
final JPanel panel = new JPanel(new BorderLayout());
panel.add(jScrollPane,BorderLayout.CENTER);
splitPane.setLeftComponent(panel);
splitPane.setRightComponent(panel2);
}
}
Any suggestions on how I should go about doing this? Please let me know if you need any clarifications.
Thank you
I am beginner in Swings. Trying to build a small application on JTree. Stuck with this issue.
I am able to load a selected folder using JFileChooser to the tree, but if I open one more folder, previous folder is replaced with the new folder. Is there any way we can open multiple folders in tree? As I keep opening folders from file chooser, it has to keep adding to existing tree. Please suggest how to achieve this?
Here is the working example I tried (picked from other posts):
import javax.swing.*;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.File;
public class TreeFrame {
public static void main(String[] args) {
JFrame frame = createFrame();
JPanel browsePanel = new JPanel();
JButton open = new JButton();
open.setPreferredSize(new Dimension(70, 25));
open.setText("Open");
final JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
JTree tree = new JTree();
JScrollPane scrollPane = new JScrollPane(tree);
Action action = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
int result = fileChooser.showOpenDialog(frame);
if (result == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
TreeModel model = new FileTreeModel(file);
tree.setModel(model);
scrollPane.add(tree);
}
}
};
open.addActionListener(action);
browsePanel.add(open);
frame.add(browsePanel, BorderLayout.WEST);
frame.add(scrollPane, BorderLayout.EAST);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static JFrame createFrame() {
JFrame frame = new JFrame("JTree Expand/Collapse example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(500, 400));
frame.setLayout(new GridLayout(1, 2));
return frame;
}
static class FileTreeModel implements TreeModel {
protected File root;
public FileTreeModel(File root) { this.root = root; }
public Object getRoot() { return root; }
public boolean isLeaf(Object node) { return ((File)node).isFile(); }
public int getChildCount(Object parent) {
String[] children = ((File)parent).list();
if (children == null) return 0;
return children.length;
}
public Object getChild(Object parent, int index) {
String[] children = ((File)parent).list();
if ((children == null) || (index >= children.length)) return null;
return new File((File) parent, children[index]);
}
public int getIndexOfChild(Object parent, Object child) {
String[] children = ((File)parent).list();
if (children == null) return -1;
String childname = ((File)child).getName();
for(int i = 0; i < children.length; i++) {
if (childname.equals(children[i])) return i;
}
return -1;
}
public void valueForPathChanged(TreePath path, Object newvalue) {}
public void addTreeModelListener(TreeModelListener l) {}
public void removeTreeModelListener(TreeModelListener l) {}
}
}
Thanks for the suggestion, found solution:
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
DefaultMutableTreeNode root = (DefaultMutableTreeNode)model.getRoot();
root.add(addNodes(null, file));
model.reload(root);
I managed to come this far using stackoverflow examples, JTree displays all the system drives and folders, wanted to display all the corresponding files from the folder as well, got all the file names in a loop need to add them, that's where I got stuck!
Please give me direction to add the files under the folder, Thanks!
CODE:
public class viewGui extends JFrame {
private FileSystemView fileSystemView;
private Desktop desktop;
private static final long serialVersionUID = 1083130296343096642L;
public static JTree tree;
private DefaultTreeModel treeModel;
private JTable table;
private ListSelectionListener listSelectionListener;
private static final LayoutManager H = new GridLayout(1, 0);
private static final LayoutManager V = new GridLayout(0, 1);
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
viewGui mainWindow = new viewGui();
mainWindow.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public viewGui() {
fileSystemView = FileSystemView.getFileSystemView();
desktop = Desktop.getDesktop();
this.setTitle("Student Record Book");
getContentPane().setLayout(H);
getContentPane().setLayout(V);
this.setPreferredSize(new Dimension(1200, 800));
this.setExtendedState(NORMAL);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.getContentPane().setLayout(null);
this.setResizable(true);
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
treeModel = new DefaultTreeModel(root);
TreeSelectionListener treeSelectionListener = new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent tse){
DefaultMutableTreeNode node = (DefaultMutableTreeNode)tse.getPath().getLastPathComponent();
System.out.println("Node: "+node);
showChildren(node);
}
};
File[] roots = fileSystemView.getRoots();
for (File fileSystemRoot : roots) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(fileSystemRoot);
root.add( node );
File[] files = fileSystemView.getFiles(fileSystemRoot, true);
for (File file : files) {
if (file.isDirectory()) {
node.add(new DefaultMutableTreeNode(file));
}
}
}
tree = new JTree(treeModel);
tree.setBounds(10, 11, 387, 740);
tree.setRootVisible(false);
tree.addTreeSelectionListener(treeSelectionListener);
tree.expandRow(0);
JScrollPane treeScroll = new JScrollPane(tree);
tree.setVisibleRowCount(15);
Dimension preferredSize = treeScroll.getPreferredSize();
Dimension widePreferred = new Dimension(200,(int)preferredSize.getHeight());
treeScroll.setPreferredSize( widePreferred );
this.setLayout(H);
this.validate();
this.add(treeScroll, BorderLayout.WEST);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
table = new JTable();
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.setAutoCreateRowSorter(true);
table.setShowVerticalLines(false);
listSelectionListener = new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent lse) {
int row = table.getSelectionModel().getLeadSelectionIndex();
}
};
table.getSelectionModel().addListSelectionListener(listSelectionListener);
JScrollPane tableScroll = new JScrollPane(table);
Dimension d = tableScroll.getPreferredSize();
tableScroll.setPreferredSize(new Dimension((int)d.getWidth(), (int)d.getHeight()/2));
getContentPane().add(tableScroll, BorderLayout.CENTER);
}
private void showChildren(final DefaultMutableTreeNode node) {
tree.setEnabled(false);
SwingWorker<Void, File> worker = new SwingWorker<Void, File>() {
#Override
public Void doInBackground() {
File file = (File) node.getUserObject();
if (file.isDirectory()) {
File[] files = fileSystemView.getFiles(file, true); //!!
if (node.isLeaf()) {
for (File child : files) {
System.out.println("child:"+child);
if (child.isDirectory()) {
publish(child);
//Need to add the file names under the folder
}
}
}
}
return null;
}
#Override
protected void process(List<File> chunks) {
for (File child : chunks) {
node.add(new DefaultMutableTreeNode(child));
if (child.isDirectory()){
}
}
}
#Override
protected void done() {
tree.setEnabled(true);
}
};
worker.execute();
}
}
Don't add all the file names in a loop. Instead, create a FileTreeModel that implements TreeModel, as shown here. The implementation simply invokes the File method listFiles() in getChild() and getIndexOfChild(). Then you can create a tree and expand any desired row; use setSelectionPath() as shown here.
TreeModel model = new FileTreeModel(new File(System.getProperty("user.dir")));
JTree tree = new JTree(model);
tree.expandRow(0);
I get only the c:\; please give me directions to get all the system drives, etc.
You can get a list of filesystem roots with File.listRoots(), as shown in Find all drive letters in Java, or FileSystemView#getRoots(), as shown in File Browser GUI.
I have a customized JTree that shows file and folders of a directory, currently it only pick the desktop directory. I could not fine any line to modify it. also fileSystemView only has getters and not setter.
Here is my working code with default 'desktop' parent directory.
public final class MainPanel extends JPanel {
private MainPanel() {
super(new BorderLayout());
final FileSystemView fileSystemView = FileSystemView.getFileSystemView();
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
final DefaultTreeModel treeModel = new DefaultTreeModel(root);
for (File fileSystemRoot: fileSystemView.getRoots()) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(new CheckBoxNode(fileSystemRoot, Status.DESELECTED));
root.add(node);
for (File file: fileSystemView.getFiles(fileSystemRoot, true)) {
if (file.isDirectory()) {
node.add(new DefaultMutableTreeNode(new CheckBoxNode(file, Status.DESELECTED)));
}
}
}
treeModel.addTreeModelListener(new CheckBoxStatusUpdateListener());
final JTree tree = new JTree(treeModel) {
#Override public void updateUI() {
setCellRenderer(null);
setCellEditor(null);
super.updateUI();
//???#1: JDK 1.6.0 bug??? Nimbus LnF
setCellRenderer(new FileTreeCellRenderer(fileSystemView));
setCellEditor(new CheckBoxNodeEditor(fileSystemView));
}
};
tree.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
tree.setRootVisible(false);
tree.addTreeSelectionListener(new FolderSelectionListener(fileSystemView));
//tree.setCellRenderer(new FileTreeCellRenderer(fileSystemView));
//tree.setCellEditor(new CheckBoxNodeEditor(fileSystemView));
tree.setEditable(true);
tree.expandRow(0);
//tree.setToggleClickCount(1);
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
add(new JScrollPane(tree));
add(new JButton(new AbstractAction("test") {
#Override public void actionPerformed(ActionEvent ae) {
System.out.println("------------------");
searchTreeForCheckedNode(tree.getPathForRow(0));
// DefaultMutableTreeNode root = (DefaultMutableTreeNode) treeModel.getRoot();
// Enumeration e = root.breadthFirstEnumeration();
// while (e.hasMoreElements()) {
// DefaultMutableTreeNode node = (DefaultMutableTreeNode) e.nextElement();
// CheckBoxNode check = (CheckBoxNode) node.getUserObject();
// if (check != null && check.status == Status.SELECTED) {
// System.out.println(check.file.toString());
// }
// }
}
}), BorderLayout.SOUTH);
setPreferredSize(new Dimension(320, 240));
}
private static void searchTreeForCheckedNode(TreePath path) {
Object o = path.getLastPathComponent();
if (!(o instanceof DefaultMutableTreeNode)) {
return;
}
DefaultMutableTreeNode node = (DefaultMutableTreeNode) o;
o = node.getUserObject();
if (!(o instanceof CheckBoxNode)) {
return;
}
CheckBoxNode check = (CheckBoxNode) o;
if (check.status == Status.SELECTED) {
System.out.println(check.file.toString());
} else if (check.status == Status.INDETERMINATE && !node.isLeaf() && node.getChildCount() >= 0) {
Enumeration e = node.children();
while (e.hasMoreElements()) {
searchTreeForCheckedNode(path.pathByAddingChild(e.nextElement()));
}
}
}
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 (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("FileSystemTreeWithCheckBox");
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
//frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(new MainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class TriStateCheckBox extends JCheckBox {
private Icon currentIcon;
#Override public void updateUI() {
currentIcon = getIcon();
setIcon(null);
super.updateUI();
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
if (currentIcon != null) {
setIcon(new IndeterminateIcon());
}
setOpaque(false);
}
});
}
}
class IndeterminateIcon implements Icon {
private static final Color FOREGROUND = new Color(50, 20, 255, 200); //TEST: UIManager.getColor("CheckBox.foreground");
private static final int SIDE_MARGIN = 4;
private static final int HEIGHT = 2;
private final Icon icon = UIManager.getIcon("CheckBox.icon");
#Override public void paintIcon(Component c, Graphics g, int x, int y) {
icon.paintIcon(c, g, x, y);
int w = getIconWidth();
int h = getIconHeight();
Graphics2D g2 = (Graphics2D) g.create();
g2.setPaint(FOREGROUND);
g2.translate(x, y);
g2.fillRect(SIDE_MARGIN, (h - HEIGHT) / 2, w - SIDE_MARGIN - SIDE_MARGIN, HEIGHT);
//g2.translate(-x, -y);
g2.dispose();
}
#Override public int getIconWidth() {
return icon.getIconWidth();
}
#Override public int getIconHeight() {
return icon.getIconHeight();
}
}
enum Status { SELECTED, DESELECTED, INDETERMINATE }
class CheckBoxNode {
public final File file;
public final Status status;
public CheckBoxNode(File file) {
this.file = file;
status = Status.INDETERMINATE;
}
public CheckBoxNode(File file, Status status) {
this.file = file;
this.status = status;
}
#Override public String toString() {
return file.getName();
}
}
class FolderSelectionListener implements TreeSelectionListener {
private final FileSystemView fileSystemView;
public FolderSelectionListener(FileSystemView fileSystemView) {
this.fileSystemView = fileSystemView;
}
#Override public void valueChanged(TreeSelectionEvent e) {
final JTree tree = (JTree) e.getSource();
final DefaultMutableTreeNode node = (DefaultMutableTreeNode) e.getPath().getLastPathComponent();
if (!node.isLeaf()) {
return;
}
CheckBoxNode check = (CheckBoxNode) node.getUserObject();
if (check == null) {
return;
}
final File parent = check.file;
if (!parent.isDirectory()) {
return;
}
final Status parentStatus = check.status == Status.SELECTED ? Status.SELECTED : Status.DESELECTED;
final DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
Task worker = new Task(fileSystemView, parent) {
#Override protected void process(List<File> chunks) {
if (!tree.isDisplayable()) {
System.out.println("process: DISPOSE_ON_CLOSE");
cancel(true);
return;
}
for (File file: chunks) {
model.insertNodeInto(new DefaultMutableTreeNode(new CheckBoxNode(file, parentStatus)), node, node.getChildCount());
//node.add(new DefaultMutableTreeNode(new CheckBoxNode(file, parentStatus)));
}
//model.reload(parent); //= model.nodeStructureChanged(parent);
}
};
worker.execute();
}
}
class Task extends SwingWorker<String, File> {
private final FileSystemView fileSystemView;
private final File parent;
public Task(FileSystemView fileSystemView, File parent) {
super();
this.fileSystemView = fileSystemView;
this.parent = parent;
}
#Override public String doInBackground() {
File[] children = fileSystemView.getFiles(parent, true);
for (File child: children) {
if (child.isDirectory()) {
publish(child);
}
}
return "done";
}
}
class FileTreeCellRenderer extends TriStateCheckBox implements TreeCellRenderer {
private final FileSystemView fileSystemView;
private final JPanel panel = new JPanel(new BorderLayout());
private final DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
public FileTreeCellRenderer(FileSystemView fileSystemView) {
super();
String uiName = getUI().getClass().getName();
if (uiName.contains("Synth") && System.getProperty("java.version").startsWith("1.7.0")) {
System.out.println("XXX: FocusBorder bug?, JDK 1.7.0, Nimbus start LnF");
renderer.setBackgroundSelectionColor(new Color(0, 0, 0, 0));
}
this.fileSystemView = fileSystemView;
panel.setFocusable(false);
panel.setRequestFocusEnabled(false);
panel.setOpaque(false);
panel.add(this, BorderLayout.WEST);
this.setOpaque(false);
}
#Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
JLabel l = (JLabel) renderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
l.setFont(tree.getFont());
if (value instanceof DefaultMutableTreeNode) {
this.setEnabled(tree.isEnabled());
this.setFont(tree.getFont());
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
if (userObject instanceof CheckBoxNode) {
CheckBoxNode node = (CheckBoxNode) userObject;
if (node.status == Status.INDETERMINATE) {
setIcon(new IndeterminateIcon());
} else {
setIcon(null);
}
setText("");
File file = (File) node.file;
l.setIcon(fileSystemView.getSystemIcon(file));
l.setText(fileSystemView.getSystemDisplayName(file));
l.setToolTipText(file.getPath());
setSelected(node.status == Status.SELECTED);
}
//panel.add(this, BorderLayout.WEST);
panel.add(l);
return panel;
}
return l;
}
#Override public void updateUI() {
super.updateUI();
if (panel != null) {
//panel.removeAll(); //??? Change to Nimbus LnF, JDK 1.6.0
panel.updateUI();
//panel.add(this, BorderLayout.WEST);
}
setName("Tree.cellRenderer");
//???#1: JDK 1.6.0 bug??? #see 1.7.0 DefaultTreeCellRenderer#updateUI()
//if (System.getProperty("java.version").startsWith("1.6.0")) {
// renderer = new DefaultTreeCellRenderer();
//}
}
}
class CheckBoxNodeEditor extends TriStateCheckBox implements TreeCellEditor {
private final FileSystemView fileSystemView;
private final JPanel panel = new JPanel(new BorderLayout());
private final DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
private File file;
public CheckBoxNodeEditor(FileSystemView fileSystemView) {
super();
this.fileSystemView = fileSystemView;
this.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
stopCellEditing();
}
});
panel.setFocusable(false);
panel.setRequestFocusEnabled(false);
panel.setOpaque(false);
panel.add(this, BorderLayout.WEST);
this.setOpaque(false);
}
#Override public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) {
//JLabel l = (JLabel) renderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
JLabel l = (JLabel) renderer.getTreeCellRendererComponent(tree, value, true, expanded, leaf, row, true);
l.setFont(tree.getFont());
setOpaque(false);
if (value instanceof DefaultMutableTreeNode) {
this.setEnabled(tree.isEnabled());
this.setFont(tree.getFont());
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
if (userObject instanceof CheckBoxNode) {
CheckBoxNode node = (CheckBoxNode) userObject;
if (node.status == Status.INDETERMINATE) {
setIcon(new IndeterminateIcon());
} else {
setIcon(null);
}
file = node.file;
l.setIcon(fileSystemView.getSystemIcon(file));
l.setText(fileSystemView.getSystemDisplayName(file));
setSelected(node.status == Status.SELECTED);
}
//panel.add(this, BorderLayout.WEST);
panel.add(l);
return panel;
}
return l;
}
#Override public Object getCellEditorValue() {
return new CheckBoxNode(file, isSelected() ? Status.SELECTED : Status.DESELECTED);
}
#Override public boolean isCellEditable(EventObject e) {
if (e instanceof MouseEvent && e.getSource() instanceof JTree) {
MouseEvent me = (MouseEvent) e;
JTree tree = (JTree) e.getSource();
TreePath path = tree.getPathForLocation(me.getX(), me.getY());
Rectangle r = tree.getPathBounds(path);
if (r == null) {
return false;
}
Dimension d = getPreferredSize();
r.setSize(new Dimension(d.width, r.height));
if (r.contains(me.getX(), me.getY())) {
if (file == null && System.getProperty("java.version").startsWith("1.7.0")) {
System.out.println("XXX: Java 7, only on first run\n" + getBounds());
setBounds(new Rectangle(0, 0, d.width, r.height));
}
//System.out.println(getBounds());
return true;
}
}
return false;
}
#Override public void updateUI() {
super.updateUI();
setName("Tree.cellEditor");
if (panel != null) {
//panel.removeAll(); //??? Change to Nimbus LnF, JDK 1.6.0
panel.updateUI();
//panel.add(this, BorderLayout.WEST);
}
//???#1: JDK 1.6.0 bug??? #see 1.7.0 DefaultTreeCellRenderer#updateUI()
//if (System.getProperty("java.version").startsWith("1.6.0")) {
// renderer = new DefaultTreeCellRenderer();
//}
}
//Copied from AbstractCellEditor
// protected EventListenerList listenerList = new EventListenerList();
// protected transient ChangeEvent changeEvent;
#Override public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
#Override public boolean stopCellEditing() {
fireEditingStopped();
return true;
}
#Override public void cancelCellEditing() {
fireEditingCanceled();
}
#Override public void addCellEditorListener(CellEditorListener l) {
listenerList.add(CellEditorListener.class, l);
}
#Override public void removeCellEditorListener(CellEditorListener l) {
listenerList.remove(CellEditorListener.class, l);
}
public CellEditorListener[] getCellEditorListeners() {
return listenerList.getListeners(CellEditorListener.class);
}
protected void fireEditingStopped() {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == CellEditorListener.class) {
// Lazily create the event:
if (changeEvent == null) {
changeEvent = new ChangeEvent(this);
}
((CellEditorListener) listeners[i + 1]).editingStopped(changeEvent);
}
}
}
protected void fireEditingCanceled() {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == CellEditorListener.class) {
// Lazily create the event:
if (changeEvent == null) {
changeEvent = new ChangeEvent(this);
}
((CellEditorListener) listeners[i + 1]).editingCanceled(changeEvent);
}
}
}
}
class CheckBoxStatusUpdateListener implements TreeModelListener {
private boolean adjusting;
#Override public void treeNodesChanged(TreeModelEvent e) {
if (adjusting) {
return;
}
adjusting = true;
Object[] children = e.getChildren();
DefaultTreeModel model = (DefaultTreeModel) e.getSource();
DefaultMutableTreeNode node;
CheckBoxNode c; // = (CheckBoxNode) node.getUserObject();
if (children != null && children.length == 1) {
node = (DefaultMutableTreeNode) children[0];
c = (CheckBoxNode) node.getUserObject();
TreePath parent = e.getTreePath();
DefaultMutableTreeNode n = (DefaultMutableTreeNode) parent.getLastPathComponent();
while (n != null) {
updateParentUserObject(n);
DefaultMutableTreeNode tmp = (DefaultMutableTreeNode) n.getParent();
if (tmp == null) {
break;
} else {
n = tmp;
}
}
model.nodeChanged(n);
} else {
node = (DefaultMutableTreeNode) model.getRoot();
c = (CheckBoxNode) node.getUserObject();
}
updateAllChildrenUserObject(node, c.status);
model.nodeChanged(node);
adjusting = false;
}
private void updateParentUserObject(DefaultMutableTreeNode parent) {
Object userObject = parent.getUserObject();
if (userObject instanceof CheckBoxNode) {
File file = ((CheckBoxNode) userObject).file;
int selectedCount = 0;
int indeterminateCount = 0;
Enumeration children = parent.children();
while (children.hasMoreElements()) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) children.nextElement();
CheckBoxNode check = (CheckBoxNode) node.getUserObject();
if (check.status == Status.INDETERMINATE) {
indeterminateCount++;
break;
}
if (check.status == Status.SELECTED) {
selectedCount++;
}
}
if (indeterminateCount > 0) {
parent.setUserObject(new CheckBoxNode(file));
} else if (selectedCount == 0) {
parent.setUserObject(new CheckBoxNode(file, Status.DESELECTED));
} else if (selectedCount == parent.getChildCount()) {
parent.setUserObject(new CheckBoxNode(file, Status.SELECTED));
} else {
parent.setUserObject(new CheckBoxNode(file));
}
}
}
private void updateAllChildrenUserObject(DefaultMutableTreeNode root, Status status) {
Enumeration breadth = root.breadthFirstEnumeration();
while (breadth.hasMoreElements()) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) breadth.nextElement();
if (root.equals(node)) {
continue;
}
CheckBoxNode check = (CheckBoxNode) node.getUserObject();
node.setUserObject(new CheckBoxNode(check.file, status));
}
}
#Override public void treeNodesInserted(TreeModelEvent e) { /* not needed */ }
#Override public void treeNodesRemoved(TreeModelEvent e) { /* not needed */ }
#Override public void treeStructureChanged(TreeModelEvent e) { /* not needed */ }
}
Any idea to change its directory ?
Use a File instead of FileSystemView to define the root.
Use File#listFiles to list the files within a specified directory instead of FileSystemView#getFiles
Something like...
File rootPath = new File(".");
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
final DefaultTreeModel treeModel = new DefaultTreeModel(root);
DefaultMutableTreeNode node = new DefaultMutableTreeNode(new CheckBoxNode(rootPath, Status.DESELECTED));
root.add(node);
for (File file : rootPath.listFiles()) {
if (file.isDirectory()) {
node.add(new DefaultMutableTreeNode(new CheckBoxNode(file, Status.DESELECTED)));
}
}
for example.
Take a look at java.io.File for more details
I have a class structure as follows:
DefaultMutableTreeNode
|_
BCStructure
|_
| Module
|_
| Section
|_
Page
Module, Section, and Page are what I actually use in my JTree. If you run the sample code below, the drag and drop works. Notice it is using DefaultMutableTreeNodes. If however, I place the code in my real applicaiont which uses the subclasses of DefualtMutableTreeNode, it does not work.
While stepping through the code, I have noticed two areas of interest. The first is this:
class TreeTransferHandler extends TransferHandler {
DataFlavor nodesFlavor;
DataFlavor[] flavors = new DataFlavor[1];
DefaultMutableTreeNode[] nodesToRemove;
public TreeTransferHandler() {
try {
String mimeType = DataFlavor.javaJVMLocalObjectMimeType
+ ";class=\""
+ javax.swing.tree.DefaultMutableTreeNode[].class.getName()
+ "\"";
nodesFlavor = new DataFlavor(mimeType);
flavors[0] = nodesFlavor;
} catch (ClassNotFoundException e) {
System.out.println("ClassNotFound: " + e.getMessage());
}
}
This is where it sets the DataFlavor. It is setting it to a DefualtMutableTreeNode array which I assume is correct since DefaultMutableTreeNode is the super class of my nodes. But this was one area where I thought the problem could lie.
The other point is while debugging this code, I get as far as:
public DataFlavor[] getTransferDataFlavors() {
return flavors;
}
before the drag and drop fails. I assume that it returns a DataFlavor that is not liked to well. This is why I think there is something wrong with the DataFlavor. Is there something more I need to do/modify in order for this to work with subclasses? Any ideas or suggestions?
Thanks!
Complete sample code:
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.tree.*;
public class TreeDragAndDrop {
private JScrollPane getContent() {
JTree tree = new JTree();
tree.setDragEnabled(true);
tree.setDropMode(DropMode.ON_OR_INSERT);
tree.setTransferHandler(new TreeTransferHandler());
tree.getSelectionModel().setSelectionMode(
TreeSelectionModel.CONTIGUOUS_TREE_SELECTION);
expandTree(tree);
return new JScrollPane(tree);
}
private void expandTree(JTree tree) {
DefaultMutableTreeNode root =
(DefaultMutableTreeNode)tree.getModel().getRoot();
Enumeration e = root.breadthFirstEnumeration();
while(e.hasMoreElements()) {
DefaultMutableTreeNode node =
(DefaultMutableTreeNode)e.nextElement();
if(node.isLeaf()) continue;
int row = tree.getRowForPath(new TreePath(node.getPath()));
tree.expandRow(row);
}
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TreeDragAndDrop().getContent());
f.setSize(400,400);
f.setLocation(200,200);
f.setVisible(true);
}
}
class TreeTransferHandler extends TransferHandler {
DataFlavor nodesFlavor;
DataFlavor[] flavors = new DataFlavor[1];
DefaultMutableTreeNode[] nodesToRemove;
public TreeTransferHandler() {
try {
String mimeType = DataFlavor.javaJVMLocalObjectMimeType +
";class=\"" +
javax.swing.tree.DefaultMutableTreeNode[].class.getName() +
"\"";
nodesFlavor = new DataFlavor(mimeType);
flavors[0] = nodesFlavor;
} catch(ClassNotFoundException e) {
System.out.println("ClassNotFound: " + e.getMessage());
}
}
public boolean canImport(TransferHandler.TransferSupport support) {
if(!support.isDrop()) {
return false;
}
support.setShowDropLocation(true);
if(!support.isDataFlavorSupported(nodesFlavor)) {
return false;
}
// Do not allow a drop on the drag source selections.
JTree.DropLocation dl =
(JTree.DropLocation)support.getDropLocation();
JTree tree = (JTree)support.getComponent();
int dropRow = tree.getRowForPath(dl.getPath());
int[] selRows = tree.getSelectionRows();
for(int i = 0; i 0 &&
target.getLevel() 0 && selRows.length == 1)
return false;
// first may have children.
for(int i = 1; i selRows.length-1) {
// Not all children of first are selected.
return false;
}
}
}
return true;
}
protected Transferable createTransferable(JComponent c) {
JTree tree = (JTree)c;
TreePath[] paths = tree.getSelectionPaths();
if(paths != null) {
// Make up a node array of copies for transfer and
// another for/of the nodes that will be removed in
// exportDone after a successful drop.
List copies =
new ArrayList();
List toRemove =
new ArrayList();
DefaultMutableTreeNode node =
(DefaultMutableTreeNode)paths[0].getLastPathComponent();
DefaultMutableTreeNode copy = copy(node);
copies.add(copy);
toRemove.add(node);
for(int i = 1; i node.getLevel()) { // child node
copy.add(copy(next));
// node already contains child
} else { // sibling
copies.add(copy(next));
toRemove.add(next);
}
}
DefaultMutableTreeNode[] nodes =
copies.toArray(new DefaultMutableTreeNode[copies.size()]);
nodesToRemove =
toRemove.toArray(new DefaultMutableTreeNode[toRemove.size()]);
return new NodesTransferable(nodes);
}
return null;
}
/** Defensive copy used in createTransferable. */
private DefaultMutableTreeNode copy(TreeNode node) {
return new DefaultMutableTreeNode(node);
}
protected void exportDone(JComponent source, Transferable data, int action) {
if((action & MOVE) == MOVE) {
JTree tree = (JTree)source;
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
// Remove nodes saved in nodesToRemove in createTransferable.
for(int i = 0; i
If you think the problem is that you subclass the DefaultMutableTreeNode, try making your DataFlavor to be an array of Object, or even better, an ArrayList:
DataFlavor.javaJVMLocalObjectMimeType + ";class=java.util.ArrayList"
This way you can return your copies list along with your transferable. Maybe it will avoid the problem.
here's a rough scetch of how to do this with lists:
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.*;
import java.util.List;
/**
* Author: Denis Tulskiy
* Date: 1/5/11
*/
public class Test extends JFrame {
class NodeA extends DefaultMutableTreeNode {
NodeA(Object userObject) {
super(userObject);
}
}
class NodeB extends DefaultMutableTreeNode {
NodeB(Object userObject) {
super(userObject);
}
}
class NodeC extends DefaultMutableTreeNode {
NodeC(Object userObject) {
super(userObject);
}
}
private static class MyTransferHandler extends TransferHandler {
#Override
public int getSourceActions(JComponent c) {
return MOVE;
}
#Override
protected Transferable createTransferable(JComponent c) {
JTree tree = (JTree) c;
ArrayList<TreeNode> nodes = new ArrayList<TreeNode>();
for (TreePath path : tree.getSelectionPaths()) {
DefaultMutableTreeNode component = (DefaultMutableTreeNode) path.getLastPathComponent();
nodes.add(component);
}
return new NodesTransferable(nodes);
}
#Override
public boolean canImport(TransferSupport support) {
return support.isDataFlavorSupported(NodesTransferable.getDataFlavor());
}
#Override
public boolean importData(TransferSupport support) {
if (!canImport(support)) {
return false;
}
JTree tree = (JTree) support.getComponent();
List<DefaultMutableTreeNode> data = null;
try {
data = (List<DefaultMutableTreeNode>) support.getTransferable().getTransferData(NodesTransferable.getDataFlavor());
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (data != null) {
Point dropPoint = support.getDropLocation().getDropPoint();
TreePath path = tree.getPathForLocation(dropPoint.x, dropPoint.y);
DefaultMutableTreeNode parent = (DefaultMutableTreeNode) path.getLastPathComponent();
for (DefaultMutableTreeNode node : data) {
node.removeFromParent();
parent.add(node);
}
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
model.reload();
}
return true;
}
}
static class NodesTransferable implements Transferable {
private static DataFlavor dataFlavor;
public static DataFlavor getDataFlavor() {
if (dataFlavor == null) {
try {
dataFlavor = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType + ";class=java.util.ArrayList");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return dataFlavor;
}
private java.util.List<TreeNode> nodes;
NodesTransferable(List<TreeNode> nodes) {
this.nodes = nodes;
}
#Override
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{getDataFlavor()};
}
#Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.match(dataFlavor);
}
#Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
return nodes;
}
}
public Test() {
JTree tree = new JTree();
tree.setDragEnabled(true);
tree.setDropMode(DropMode.ON_OR_INSERT);
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
NodeA child = new NodeA("nodea");
root.add(child);
child.add(new NodeB("nodeb"));
child.add(new NodeC("nodec"));
tree.setModel(new DefaultTreeModel(root));
tree.setTransferHandler(new MyTransferHandler());
setLayout(new BorderLayout());
add(tree, BorderLayout.CENTER);
setSize(300, 400);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new Test().setVisible(true);
}
}