Swing - JTree multiple root folders selected from JFileChooser - java

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);

Related

Get multiple root directories on JTree to select the leaf - Swing

I have been using JTree to get the multiple root directories of the system, using the example FileTreeModel.java to achieve it. And also trying to get the selected leaf (path) but it throws cast error, please give me some directions on this, have posted the code so far have tried. Thanks.
import java.io.File;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import java.io.File;
public class FileTreeDemo {
public static void main(String[] args) {
// Figure out where in the filesystem to start displaying
File root;
if (args.length > 0) {
root = new File(args[0]);
//System.out.println(args.length);
}
else root = new File(System.getProperty("user.home"));
//System.out.println(args.length);
// Create a TreeModel object to represent our tree of files
FileTreeModel model = new FileTreeModel(root);
// Create a JTree and tell it to display our model
JTree tree = new JTree();
tree.setModel(model);
tree.setRootVisible(true);
tree.setShowsRootHandles(true);
//tree.setShowsRootHandles(true);
// The JTree can get big, so allow it to scroll.
JScrollPane scrollpane = new JScrollPane(tree);
// Display it all in a window and make the window appear
JFrame frame = new JFrame("FileTreeDemo");
frame.getContentPane().add(scrollpane, "Center");
frame.setSize(400,600);
frame.setVisible(true);
// Add a listener
tree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) e
.getPath().getLastPathComponent();
System.out.println("You selected " + node);
}
});
}
}
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) {}
}
In your model you store File's instead of DefaultMutableTreeNode, because of you get ClassCastException here:
DefaultMutableTreeNode node = (DefaultMutableTreeNode)e.getPath().getLastPathComponent();
Change your listener like next:
tree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
File node = (File) e.getPath().getLastPathComponent();
System.out.println("You selected " + node);
}
});

insertNodeInto function only works in first insertion (works for leaf node)

Say I'm coding for an editable tree file system and adding an action listener for my "add child" button. That is, once I select a node in the tree and click the "Add child" button. There should be a new node "New" becoming its child, which was showed in Fig.1.
(Sorry I don't have 10 reputation to post images.. But probably you can run the complete code below.)
But the thing is my listener only works in first insertion, which means it only works for leaf node.
When I'm trying to add a new node into "Thing" node, the tree doesn't change. While the figure didn't change, the return value of .childCount() function return did change according to what the console display.
addChildButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent action)
{
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) m_tree.
getLastSelectedPathComponent();
if (selectedNode == null)
{
System.out.println("selected null");
return ;
}
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("New");
System.out.println(selectedNode.getChildCount());
m_model.insertNodeInto(newNode, selectedNode,
selectedNode.getChildCount());
// display the new node
m_tree.scrollPathToVisible(new TreePath(newNode.getPath()));
}
});
For the ones who want to run the program, the complete code is here:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.tree.*;
public class TreeEditTest
{
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new TreeEditFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
class TreeEditFrame extends JFrame
{
public TreeEditFrame()
{
setTitle("TreeEditTest");
setSize(M_DEFAULT_WIDTH, M_DEFAULT_HEIGHT);
// construct tree
TreeNode root = makeSampleTree();
m_model = new DefaultTreeModel(root);
m_tree = new JTree(root);
m_tree.setEditable(true);
// add scroll pane with tree
JScrollPane scrollPane = new JScrollPane(m_tree);
add(scrollPane, BorderLayout.CENTER);
// make buttons
makeButtons();
}
private TreeNode makeSampleTree()
{
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Thing");
DefaultMutableTreeNode pizza = new DefaultMutableTreeNode("Pizza");
DefaultMutableTreeNode pizzaBase = new DefaultMutableTreeNode("PizzaBase");
DefaultMutableTreeNode pizzaTopping = new DefaultMutableTreeNode("PizzaTopping");
root.add(pizza);
root.add(pizzaBase);
root.add(pizzaTopping);
DefaultMutableTreeNode deepPanBase = new DefaultMutableTreeNode("DeepPanBase");
DefaultMutableTreeNode thinAndCrispyBase = new DefaultMutableTreeNode("ThinAndCrispyBase");
pizzaBase.add(deepPanBase);
pizzaBase.add(thinAndCrispyBase);
return root;
}
private void makeButtons()
{
JPanel panel = new JPanel();
JButton addChildButton = new JButton("Add Child");
JButton addSiblingButton = new JButton("Add Sibling");
JButton deleteButton = new JButton("Delete");
addChildButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent action)
{
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) m_tree.
getLastSelectedPathComponent();
if (selectedNode == null)
{
System.out.println("selected null");
return ;
}
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("New");
System.out.println(selectedNode.getChildCount());
m_model.insertNodeInto(newNode, selectedNode,
selectedNode.getChildCount());
// display the new node
m_tree.scrollPathToVisible(new TreePath(newNode.getPath()));
}
});
addSiblingButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent action)
{
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) m_tree.
getLastSelectedPathComponent();
if (selectedNode == null)
{
System.out.println("selected null");
return ;
}
DefaultMutableTreeNode parent = (DefaultMutableTreeNode) selectedNode.
getParent();
if (parent == null)
{
System.out.println("parent null");
return ;
}
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("New");
int selectedIndex = parent.getIndex(selectedNode);
// System.out.println(parent.getChildCount());
// m_model.insertNodeInto(newNode, parent, parent.getChildCount());
System.out.println(selectedIndex+1);
m_model.insertNodeInto(newNode, parent, selectedIndex+1);
// now display the new node
TreeNode[] nodes = m_model.getPathToRoot(newNode);
TreePath path = new TreePath(nodes);
m_tree.scrollPathToVisible(path);
}
});
deleteButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent action)
{
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) m_tree.
getLastSelectedPathComponent();
if (selectedNode == null)
{
System.out.println("selected null");
return ;
}
DefaultMutableTreeNode parent = (DefaultMutableTreeNode) selectedNode.
getParent();
if (parent == null)
{
System.out.println("Cannot delete the \"Thing\" node");
return ;
}
m_model.removeNodeFromParent(selectedNode);
}
});
panel.add(addChildButton);
panel.add(addSiblingButton);
panel.add(deleteButton);
add(panel, BorderLayout.NORTH);
}
private DefaultTreeModel m_model;
private JTree m_tree;
private static final int M_DEFAULT_WIDTH = 400;
private static final int M_DEFAULT_HEIGHT = 200;
}
That's simply because the JTree doesn't use your model. It uses another model it creates from the root tree you passed as argument to the tree constructor. Replace
m_tree = new JTree(root);
by
m_tree = new JTree(m_model);

How to collapse JTree nodes?

I want to implement a requirement where in I have to collapse all child nodes of JTree.
I am using jdk1.6.
Note: Only the child nodes of root element are to be collapsed on button click.
Here is my code:
private static void collapseAll(JTree tree, TreePath parent) {
TreeNode node = (TreeNode)parent.getLastPathComponent();
if (!node.isLeaf() && node.getChildCount()>=0) {
Enumeration e = node.children();
while (e.hasMoreElements()) {
TreeNode n = (TreeNode)e.nextElement();
TreePath path = parent.pathByAddingChild(n);
collapseAll(tree, path);
}
}
tree.collapsePath(parent);
}
If I understand your requirement you might be able to use the following code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TreeCollapseTest {
private final JTree tree = new JTree();
public JComponent makeUI() {
JPanel p = new JPanel(new BorderLayout());
p.add(new JButton(new AbstractAction("collapse") {
#Override public void actionPerformed(ActionEvent e) {
// if (tree.isRootVisible()) {
int row = tree.getRowCount() - 1;
//while (row >= 0) { //collapses all nodes
while (row > 0) { //collapses only child nodes of root node
tree.collapseRow(row);
row--;
}
}
}), BorderLayout.SOUTH);
p.add(new JScrollPane(tree));
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new TreeCollapseTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
Try this:
for(int i = jTree.getRowCount() - 1; i >= 0; i--){
jTree.collapseRow(i);
}

Recursively reading a Directory into an ArrayList/Array in Java

I am currently stuck at reading a directory into an ArrayList or better an Array in Java.
I want to use the Data in a JTree.
That's the code I currently use:
//After the definiton of the Class
private ArrayList<File> files = new ArrayList<File>();
// In the main method
this.parse(new File("."));
DefaultMutableTreeNode root = processHierarchy(files.toArray());
this.tree = new JTree(root);
private void parse(File parent)
{
files.add(parent);
if(parent.isDirectory())
{
System.out.println("DIR: "+parent.getName());
String[] child = parent.list();
if(child != null)
{
for(int i = 0; i < child.length; i++)
{
File f = new File(parent, child[i]);
this.parse(f);
}
}
}
else
{
System.out.println("FILE: "+parent.getName());
}
}
Anyone got an idea?
I found this code online that searches a path and then displays it in a JTree.
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.event.*;
import java.awt.*;
import java.util.*;
import java.io.*;
public class SimpleTree extends JPanel {
JTree tree;
DefaultMutableTreeNode root;
public SimpleTree() {
root = new DefaultMutableTreeNode("root", true);
getList(root, new File("C:\\Program Files")); // change path here
setLayout(new BorderLayout());
tree = new JTree(root);
tree.setRootVisible(false);
add(new JScrollPane((JTree)tree),"Center");
}
public Dimension getPreferredSize(){
return new Dimension(200, 120);
}
public void getList(DefaultMutableTreeNode node, File f) {
if(!f.isDirectory()) {
// We keep only JAVA source file for display in this HowTo
if (f.getName().endsWith("java")) {
System.out.println("FILE - " + f.getName());
DefaultMutableTreeNode child = new DefaultMutableTreeNode(f);
node.add(child);
}
}
else {
System.out.println("DIRECTORY - " + f.getName());
DefaultMutableTreeNode child = new DefaultMutableTreeNode(f);
node.add(child);
File fList[] = f.listFiles();
for(int i = 0; i < fList.length; i++)
getList(child, fList[i]);
}
}
public static void main(String s[]){
MyJFrame frame = new MyJFrame("Directory explorer");
}
}
class WindowCloser extends WindowAdapter {
public void windowClosing(WindowEvent e) {
Window win = e.getWindow();
win.setVisible(false);
System.exit(0);
}
}
class MyJFrame extends JFrame {
JButton b1, b2, b3;
SimpleTree panel;
MyJFrame(String s) {
super(s);
panel = new SimpleTree();
getContentPane().add(panel,"Center");
setSize(300,300);
setVisible(true);
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowCloser());
}
}
Source: http://www.rgagnon.com/javadetails/java-0324.html

How do I auto-expand a JTree when setting a new TreeModel?

I have a custom JTree and a custom JModel; I would for the JTree to "auto-expand" when I give it a new model. At the moment, it simply collapse all the nodes to the root.
Here is an example:
private class CustomTree extends JTree {
#Override
public boolean isExpanded(TreePath path) {
return ((Person) path.getLastPathComponent).hasChildren();
}
private class CustomTreeModel extends TreeModel {
// ... omitting various implementation details
#Override
public boolean isLeaf(Object object) {
return !((Person) object).hasChildren();
}
}
Model model = new Model();
Person bob = new Person();
Person alice = new Person();
bob.addChild(alice);
model.setRoot(bob);
JTree tree = new CustomTree(new CustomTreeModel(model));
At this point, the tree correctly displays:
- BOB
- ALICE
where Alice is a child of Bob (both in the data and in the visual tree)
However, if I call:
tree.setModel(new CustomTreeModel(model));
everything is collapsed:
+ BOB
Is there a way to "auto-expand" everything in the tree when setting a new model?
The following worked for me (called after setting the new model):
for (int i = 0; i < tree.getRowCount(); i++) {
tree.expandRow(i);
}
I had a similar problem.
Your solution (as posted https://stackoverflow.com/a/15211697/837530) seemed to work for me only for the top level tree nodes.
But I needed to expand all the a descendants node. So I solved it with the following recursive method:
private void expandAllNodes(JTree tree, int startingIndex, int rowCount){
for(int i=startingIndex;i<rowCount;++i){
tree.expandRow(i);
}
if(tree.getRowCount()!=rowCount){
expandAllNodes(tree, rowCount, tree.getRowCount());
}
}
which is invoked with
expandAllNodes(tree, 0, tree.getRowCount());
where, tree is a JTree.
Unless someone has a better solution.
There's also this non-recursive version.
private void expandAllNodes(JTree tree) {
int j = tree.getRowCount();
int i = 0;
while(i < j) {
tree.expandRow(i);
i += 1;
j = tree.getRowCount();
}
}
this worked for me..
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeNode;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.Enumeration;
public class JTreeNodeAutoExpandCollapse extends JFrame {
public JTreeNodeAutoExpandCollapse() throws HeadlessException {
initializeUI();
}
private void initializeUI() {
setSize(200, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
DefaultMutableTreeNode chapter1 = new DefaultMutableTreeNode("Chapter 1");
DefaultMutableTreeNode sub1 = new DefaultMutableTreeNode("1.1");
DefaultMutableTreeNode sub2 = new DefaultMutableTreeNode("1.2");
DefaultMutableTreeNode sub3 = new DefaultMutableTreeNode("1.3");
DefaultMutableTreeNode sub31 = new DefaultMutableTreeNode("1.3.1");
DefaultMutableTreeNode sub32 = new DefaultMutableTreeNode("1.3.2");
root.add(chapter1);
chapter1.add(sub1);
chapter1.add(sub2);
chapter1.add(sub3);
sub3.add(sub31);
sub3.add(sub32);
final JTree tree = new JTree(root);
expandTree(tree, false);
JScrollPane pane = new JScrollPane(tree);
pane.setPreferredSize(new Dimension(200, 200));
JPanel buttonPanel = new JPanel(new BorderLayout());
JButton expandAll = new JButton("Expand All");
expandAll.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
expandTree(tree, true);
}
});
JButton collapseAll = new JButton("Collapse All");
collapseAll.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
expandTree(tree, false);
}
});
buttonPanel.add(expandAll, BorderLayout.WEST);
buttonPanel.add(collapseAll, BorderLayout.EAST);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(pane, BorderLayout.CENTER);
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
}
private void expandTree(JTree tree, boolean expand) {
TreeNode root = (TreeNode) tree.getModel().getRoot();
expandAll(tree, new TreePath(root), expand);
}
private void expandAll(JTree tree, TreePath path, boolean expand) {
TreeNode node = (TreeNode) path.getLastPathComponent();
if (node.getChildCount() >= 0) {
Enumeration enumeration = node.children();
while (enumeration.hasMoreElements()) {
TreeNode n = (TreeNode) enumeration.nextElement();
TreePath p = path.pathByAddingChild(n);
expandAll(tree, p, expand);
}
}
if (expand) {
tree.expandPath(path);
} else {
tree.collapsePath(path);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JTreeNodeAutoExpandCollapse().setVisible(true);
}
});
}
}
public void expandTree(){
int row = 1;
while (row++ < tree.getRowCount()){
tree.expandRow(row);
}
public void collapseTree(){
int row = tree.getRowCount() - 1;
while (row-- > 0){
tree.collapseRow(row);
}
}

Categories