How to Search a Particular Node in Jtree and Make That Node Expanded

How to expand to specific TreeNode in JTree

Try this example ... it allows you to search for a node by name and will expand to the first node found

    import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

public class TreeDemo extends JFrame implements ActionListener{
private static final long serialVersionUID = 1L;
public JTree tree;
public JButton button;

public TreeDemo() {

button = new JButton("Find Queen");

button.addActionListener(this);

tree = new JTree();
DefaultMutableTreeNode root = new DefaultMutableTreeNode( "Deck" );
DefaultMutableTreeNode itemClubs= new DefaultMutableTreeNode( "Clubs" );
addAllCard( itemClubs );
root.add( itemClubs );

DefaultMutableTreeNode itemDiamonds = new DefaultMutableTreeNode( "Diamonds" );
addAllCard( itemDiamonds );
root.add( itemDiamonds );

DefaultMutableTreeNode itemSpades = new DefaultMutableTreeNode( "Spades" );
addAllCard( itemSpades );
root.add( itemSpades );

DefaultMutableTreeNode itemHearts = new DefaultMutableTreeNode( "Hearts" );
addAllCard( itemHearts );
root.add( itemHearts );

DefaultTreeModel treeModel = new DefaultTreeModel( root );
tree = new JTree( treeModel );

JScrollPane scrollPane = new JScrollPane(tree);
getContentPane().add(scrollPane, BorderLayout.CENTER);
getContentPane().add(button, BorderLayout.NORTH);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(375, 400);
}

public void addAllCard( DefaultMutableTreeNode suit ) {
suit.add( new DefaultMutableTreeNode( "Ace" ) );
suit.add( new DefaultMutableTreeNode( "Two" ) );
suit.add( new DefaultMutableTreeNode( "Three" ) );
suit.add( new DefaultMutableTreeNode( "Four" ) );
suit.add( new DefaultMutableTreeNode( "Five" ) );
suit.add( new DefaultMutableTreeNode( "Six" ) );
suit.add( new DefaultMutableTreeNode( "Seven" ) );
suit.add( new DefaultMutableTreeNode( "Eight" ) );
suit.add( new DefaultMutableTreeNode( "Nine" ) );
suit.add( new DefaultMutableTreeNode( "Ten" ) );
suit.add( new DefaultMutableTreeNode( "Jack" ) );
suit.add( new DefaultMutableTreeNode( "Queen" ) );
suit.add( new DefaultMutableTreeNode( "King" ) );
}

public final DefaultMutableTreeNode findNode(String searchString) {

List<DefaultMutableTreeNode> searchNodes = getSearchNodes((DefaultMutableTreeNode)tree.getModel().getRoot());
DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();

DefaultMutableTreeNode foundNode = null;
int bookmark = -1;

if( currentNode != null ) {
for(int index = 0; index < searchNodes.size(); index++) {
if( searchNodes.get(index) == currentNode ) {
bookmark = index;
break;
}
}
}

for(int index = bookmark + 1; index < searchNodes.size(); index++) {
if(searchNodes.get(index).toString().toLowerCase().contains(searchString.toLowerCase())) {
foundNode = searchNodes.get(index);
break;
}
}

if( foundNode == null ) {
for(int index = 0; index <= bookmark; index++) {
if(searchNodes.get(index).toString().toLowerCase().contains(searchString.toLowerCase())) {
foundNode = searchNodes.get(index);
break;
}
}
}
return foundNode;
}

private final List<DefaultMutableTreeNode> getSearchNodes(DefaultMutableTreeNode root) {
List<DefaultMutableTreeNode> searchNodes = new ArrayList<DefaultMutableTreeNode>();

Enumeration<?> e = root.preorderEnumeration();
while(e.hasMoreElements()) {
searchNodes.add((DefaultMutableTreeNode)e.nextElement());
}
return searchNodes;
}

public static void main(String[] args) {
TreeDemo app = new TreeDemo();
app.setVisible(true);

}

public void actionPerformed(ActionEvent e) {
DefaultMutableTreeNode node = findNode("Queen");
if( node != null ) {
TreePath path = new TreePath(node.getPath());
tree.setSelectionPath(path);
tree.scrollPathToVisible(path);
}
}
}

Expanding specific JTree Node with FileTree as TreeModel

After exploring about TreeModel, I found a solution. I have extended the DefaultMutableTreeNode as FileMutuableTreeNode and wherever DefaultMutableTreeNode is used with TreeModel, I have replaced it with FileMutuableTreeNode. Hope it is useful for those who are reading this in near future.

The actual question is based on the below reference link.

Reference : http://www.javaprogrammingforums.com/java-swing-tutorials/7944-how-use-jtree-create-file-system-viewer-tree.html

FileSysBrowser.java

//Reference : http://www.javaprogrammingforums.com/java-swing-tutorials/7944-how-use-jtree-create-file-system-viewer-tree.html
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.JButton;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTree;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

public class FileSysBrowser extends JFrame {

public JTree fileTree;
private FileSystemModel fileSystemModel;

public FileSysBrowser(String directory) {
// System.out.println("REPO : " + Arrays.toString(REPO_PATH));
setTitle("FileSysBrowser");
fileSystemModel = new FileSystemModel(new FileMutableTreeNode(new File(directory)));
fileTree = new JTree(fileSystemModel);
fileTree.setEditable(false);
JPanel pnlMain = new JPanel(new BorderLayout(5, 5));
pnlMain.add(new JScrollPane(fileTree), BorderLayout.CENTER);
final JButton btn = new JButton("click");
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new Thread() {
@Override
public void run() {
btn.setEnabled(false);
expandNodePath("/repo/dinesh/trunk/Design/");
btn.setEnabled(true);
}
}.start();

}
});
pnlMain.add(btn, BorderLayout.PAGE_END);
getContentPane().add(pnlMain);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(640, 480);
setVisible(true);
}
//Reference : https://stackoverflow.com/questions/8210630/how-to-search-a-particular-node-in-jtree-and-make-that-node-expanded
//Thanks to 'trashgod' for the answer
private FileMutableTreeNode findNode(FileMutableTreeNode root, String s) {
@SuppressWarnings("unchecked")
Enumeration<FileMutableTreeNode> e = root.depthFirstEnumeration();
while (e.hasMoreElements()) {
FileMutableTreeNode node = e.nextElement();
if (node.toString().equals(s)) {
// return new TreePath(node.getPath());
return node;
}
}
return null;
}

private void expandNodePath(String filePath) {
if(filePath.startsWith("/")) {
filePath = filePath.replaceFirst("/", "");
}
String[] files = filePath.split("/");
//Initializing the parent node as 'root'
FileMutableTreeNode parentNode = fileSystemModel.getRoot();
for (String file : files) {
FileMutableTreeNode childNode = findNode(parentNode, file);
fileTree.expandPath(new TreePath(childNode.getPath()));
// Then setting the current 'child' node as parent node
// for the next iteration
parentNode = childNode;
}

// The below code is what the expansion of above for loop code.
// For ease of understanding, I have kept it for others.
// FileMutableTreeNode repoNode = findNode(fileSystemModel.getRoot(), "repo");
// fileTree.expandPath(new TreePath(repoNode.getPath()));
// FileMutableTreeNode dineshNode = findNode(repoNode, "dinesh");
// fileTree.expandPath(new TreePath(dineshNode.getPath()));

}

public static void main(String args[]) {
// System.out.println(new File("/").getName());

FileSysBrowser fileSysBrowser = new FileSysBrowser("/");

JTree jt = fileSysBrowser.fileTree;

jt.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
TreePath tp = e.getNewLeadSelectionPath();
if (tp != null) {
System.out.println(tp);
// System.out.println(tp.getLastPathComponent());
}
}
});
}
}

class FileSystemModel implements TreeModel {

// private File root;
private FileMutableTreeNode root;

private final Vector listeners = new Vector();

public FileSystemModel(FileMutableTreeNode rootDirectory) {
root = rootDirectory;
}

@Override
public FileMutableTreeNode getRoot() {
return root;
}

@Override
public Object getChild(Object parent, int index) {

FileMutableTreeNode parentNode = (FileMutableTreeNode) parent;
File directory = parentNode.getFileNode();
String[] children = directory.list();
Arrays.sort(children);
String currentChild = children[index];
FileMutableTreeNode childNode = new FileMutableTreeNode(new File(directory, currentChild));
if (parentNode.toString().equals("/")) {
root.add(childNode);
} else {
parentNode.add(childNode);
}
return childNode;
}

@Override
public int getChildCount(Object parent) {
FileMutableTreeNode fileNode = (FileMutableTreeNode) parent;
File file = fileNode.getFileNode();
if (file.isDirectory()) {
String[] fileList = file.list();
if (fileList != null) {
return file.list().length;
}
}
return 0;
}

@Override
public boolean isLeaf(Object node) {
FileMutableTreeNode fileNode = (FileMutableTreeNode) node;
File file = fileNode.getFileNode();
return file.isFile();
}

@Override
public int getIndexOfChild(Object parent, Object child) {
FileMutableTreeNode parentNode = (FileMutableTreeNode) parent;
File directory = parentNode.getFileNode();
FileMutableTreeNode childNode = (FileMutableTreeNode) child;
File file = childNode.getFileNode();
String[] children = directory.list();
for (int i = 0; i < children.length; i++) {
if (file.getName().equals(children[i])) {
return i;
}
}
return -1;

}

@Override
public void valueForPathChanged(TreePath path, Object value) {
System.out.println("valueForPathChanged -> path : " + path + ", value : " + value);
}

@Override
public void addTreeModelListener(TreeModelListener listener) {
listeners.add(listener);
}

@Override
public void removeTreeModelListener(TreeModelListener listener) {
listeners.remove(listener);
}

}

FileMutableTreeNode .java

import java.io.File;
import javax.swing.tree.DefaultMutableTreeNode;

class FileMutableTreeNode extends DefaultMutableTreeNode {

private File fileNode = null;

public FileMutableTreeNode(File fileNode) {
this.fileNode = fileNode;
}

public File getFileNode() {
return fileNode;
}

@Override
public String toString() {
//For root, returning the name as '/'
if (fileNode.getAbsolutePath().equals("/")) {
return "/";
} else {
return fileNode.getName();
}
}
}

How to catch JTree node expanded event

Use the (funny named) TreeWillExpandListener.

TreeWillExpandListener treeWillExpandListener = new TreeWillExpandListener() {
public void treeWillCollapse(TreeExpansionEvent treeExpansionEvent)
throws ExpandVetoException {

TreePath path = treeExpansionEvent.getPath();
DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();

//Print the name of the node if toString() was implemented
String data = node.getUserObject().toString();
System.out.println("WillCollapse: " + data);

}

public void treeWillExpand(TreeExpansionEvent treeExpansionEvent) throws ExpandVetoException {

TreePath path = treeExpansionEvent.getPath();
DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();

//print the name of the node if toString was implemented
String data = node.getUserObject().toString();
System.out.println("WillExpand: " + data);

}
};

tree.addTreeWillExpandListener(treeWillExpandListener);

Is there a better way to test JTree node expanded or not?

JTree.java:

 /**
* Returns true if the node identified by the path is currently expanded,
*
* @param path the <code>TreePath</code> specifying the node to check
* @return false if any of the nodes in the node's path are collapsed,
* true if all nodes in the path are expanded
*/
public boolean isExpanded(TreePath path);

Beautiful, JavaDoc :-)

The expanded state of a Node is not in the TreeModel but in the JTree.

How to get a specific JTree node given a string array

First, you need to fetch the tree model with getModel() method. Once you have the model, it has the getRoot() method, to fetch the root of the tree. After that, you can follow with calls to getChild(Object parent, int index) and check if any of the children has the same name as the one provided in the String array. If you find such one, you can again call getChild(Object parent, int index), etc... until you arrive at the last String from the array. Then you have the corresponding tree node. You need to actually cast the tree nodes to DefaultMutableTreeNode, as the TreeModel uses Object as the tree elements (for pre-1.7 Java).

Expanding specific JTree path

Swing GUI objects should be constructed and manipulated only on the event dispatch thread.

Sample Image

import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;

public class SelectableTree extends JFrame implements TreeSelectionListener {

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
new SelectableTree();
}
});
}
DefaultMutableTreeNode root;
DefaultMutableTreeNode e1 = new DefaultMutableTreeNode("1");
DefaultMutableTreeNode e2 = new DefaultMutableTreeNode("2");
DefaultMutableTreeNode e3 = new DefaultMutableTreeNode("3");
DefaultMutableTreeNode e11 = new DefaultMutableTreeNode("1.1");
DefaultMutableTreeNode e22 = new DefaultMutableTreeNode("2.2");
DefaultMutableTreeNode e33 = new DefaultMutableTreeNode("3.3");
DefaultMutableTreeNode e111 = new DefaultMutableTreeNode("1.1.1");
DefaultMutableTreeNode e222 = new DefaultMutableTreeNode("2.2.2");
DefaultMutableTreeNode e333 = new DefaultMutableTreeNode("3.3.3");
DefaultMutableTreeNode aChild;
private JTree tree;
private JTextField currentSelectionField;

public SelectableTree() {
super("JTree Selections");
setDefaultCloseOperation(EXIT_ON_CLOSE);
root = new DefaultMutableTreeNode("Root");
root.add(e1);
root.add(e2);
root.add(e3);
e1.add(e11);
e2.add(e22);
e3.add(e33);
e11.add(e111);
e22.add(e222);
e33.add(e333);

tree = new JTree(root);
tree.addTreeSelectionListener(this);
add(new JScrollPane(tree), BorderLayout.CENTER);
currentSelectionField = new JTextField("Current Selection: NONE");
add(currentSelectionField, BorderLayout.SOUTH);
setSize(250, 275);
setLocationRelativeTo(null);
setVisible(true);
}

@Override
public void valueChanged(TreeSelectionEvent event) {
tree.expandPath(new TreePath(e11.getPath()));
currentSelectionField.setText(event.getPath().toString());
}
}

Java JTree expand only level one nodes

Thanks for the quick response guys. However I have now found the simple solution I was looking for. For some reason I just couldn't see DefaultMutableTreeNode.getLevel() in the JavaDocs! FYI what I'm doing now is:

DefaultMutableTreeNode currentNode = treeTop.getNextNode();
do {
if (currentNode.getLevel() == 1)
myTree.expandPath(new TreePath(currentNode.getPath()));
currentNode = currentNode.getNextNode();
} while (currentNode != null);


Related Topics



Leave a reply



Submit