Saving the Expansion State of a JTree

Articles —> Saving the Expansion State of a JTree

A JTree is a java Swing component that displays hierarchical data in a tree-like user interface. A JTree models a tree data structure, in which nodes with children can be expanded or retracted with the click of the mouse. Often it is desirable for a java program to save the expanded state of a JTree, either within a single runtime (for instance after reloading the model - a process which may affect expansion state) or between runtimes (after quit and restart) of the application.

Saving the expanded state of a JTree can be as simple as saving indexes of the expanded nodes. A JTree has a particular number of rows, specified by the number of visible nodes. One can loop over these visible nodes, saving the index of each row which is found to be expanded. In the class below, the expanded row indexes are saved and restored as a list of indexes represented as a comma delimited String.


import javax.swing.JFrame;

import javax.swing.JScrollPane;

import javax.swing.JTree;

import javax.swing.tree.TreePath;

/**

 * Utility class that can be used to retrieve and/or restore the expansion state of a JTree. 

 * @author G. Cope

 *

 */

public class TreeExpansionUtil {



	private final JTree tree;

	

	/**

	 * Constructs a new utility object based upon the parameter JTree

	 * @param tree

	 */

	public TreeExpansionUtil(JTree tree){

		this.tree = tree;

	}

	

	/**

	 * Retrieves the expansion state as a String, defined by a comma delimited list of 

	 * each row node that is expanded.

	 * @return

	 */

	public String getExpansionState(){

		StringBuilder sb = new StringBuilder();

		for ( int i = 0; i < tree.getRowCount(); i++ ){

			if ( tree.isExpanded(i) ){

				sb.append(i).append(",");

			}

		}

		return sb.toString();

	}

	

	/**

	 * Sets the expansion state based upon a comma delimited list of row indexes that 

	 * are expanded. 

	 * @param s

	 */

	public void setExpansionState(String s){

		String[] indexes = s.split(",");

		for ( String st : indexes ){

			int row = Integer.parseInt(st);

			tree.expandRow(row);

		}

	}

}



The above class can be constructed with the specified JTree, and its method used to get the expanded state as a String (which can, for instance, be saved to a file for later use), and restore the state from a String.


/**

 * Example main method to demonstrate how the expansion state of a JTree is saved. 

 * @param args

 * @throws Exception

 */

public static void main(String[] args) throws Exception{

	SwingUtilities.invokeLater(new Runnable(){



		@Override

		public void run() {

			DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");

			DefaultMutableTreeNode c1 = new DefaultMutableTreeNode("Child 1");

			DefaultMutableTreeNode c2 = new DefaultMutableTreeNode("Child 2");

			DefaultMutableTreeNode c3 = new DefaultMutableTreeNode("Child 3");

			DefaultMutableTreeNode c4 = new DefaultMutableTreeNode("Child 4");

			DefaultMutableTreeNode c11 = new DefaultMutableTreeNode("Grandchild 1");

			DefaultMutableTreeNode c12 = new DefaultMutableTreeNode("Grandchild 2");

			DefaultMutableTreeNode c13 = new DefaultMutableTreeNode("Grandchild 3");

			DefaultMutableTreeNode c14 = new DefaultMutableTreeNode("Grandchild 4");

			root.add(c1);

			root.add(c2);

			root.add(c3);

			root.add(c4);

			c1.add(c11);

			c11.add(c12);

			c4.add(c13);

			c4.add(c14);

			

			

			final DefaultTreeModel model = new DefaultTreeModel(root);

			final JTree tree = new JTree(model);

			TreePath path = new TreePath(model.getPathToRoot(c11));

			tree.expandPath(path);

			path = new TreePath(model.getPathToRoot(c4));

			tree.expandPath(path);

			JFrame frame = new JFrame();

			

			

			JScrollPane scroller = new JScrollPane(tree);

			frame.getContentPane().add(scroller);

			frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

			frame.pack();

			frame.setVisible(true);

			Runnable runner = new Runnable(){

				@Override

				public void run(){

					final TreeExpansionUtil expander = new TreeExpansionUtil(tree);

					final String state = expander.getExpansionState();

					System.out.println(state);

					try{

						Thread.sleep(1000);

						SwingUtilities.invokeAndWait(new Runnable(){



							@Override

							public void run() {

								System.out.println("Collapsing Root Node");

								tree.collapseRow(0);

							}

							

						});

					}catch(InterruptedException e){

						e.printStackTrace();

					} catch (InvocationTargetException e) {

						e.printStackTrace();

					}

					

					try{

						Thread.sleep(1000);

						SwingUtilities.invokeAndWait(new Runnable(){



							@Override

							public void run() {

								System.out.println("Restoring expanded state");

								expander.setExpansionState(state);

							}

							

						});

					}catch(InterruptedException e){

						e.printStackTrace();

					}catch (InvocationTargetException e) {

						e.printStackTrace();

					}

					

					try{

						Thread.sleep(1000);

					}catch(InterruptedException e){

						e.printStackTrace();

					}

				}

			};

			new Thread(runner).start();

		}

		

	});

}

The above code demonstrates the use of the utility class, and demonstrates - using a timer for animation - how the JTree expansion state is saved and restored.

screen shot of a JTree expanded state


There are no comments on this article.

Back to Articles


© 2008-2022 Greg Cope