In the previous post we looked at displaying information in a hierarchy using JTree.
Now all this is fine but, usually when we use a JTree it is because we want to be able to select an item, one or more. For our example let us concern ourselves with selecting a single item and displaying the detail associated with that item.
To do this we need to use the event driven notification for the JTree. There are different events for different situations; in our case we are interested in the selection event. When one of the options in the JTree is selected then we want to know about this.
Now the JTree comes with the ability to notify other objects when a node is selected, so the good news is we can just make use of that. What we need to do is have an object that will take on responsibility for listening to events from the JTree and do something with these events. Any object can fulfil this roll all we need to do is change the class to say that it implements the TreeSelectionListener interface which is the interface required for JTree to be able to notify of selection changes. Once we have stated the class implements the interface then we need to implement the methods for that interface and in this case there is a single method call valueChanged(TreeSelectionEvent). Within this method we can process the event information and take some action.
Well that’s the general approach now down to the implementation. We will now change our application so that it makes use of a split pane and have on one side the JTree and on the other the information associated with the selected node that we want to display.
First off we build a simple class that creates a JPanel and has a single JLabel field which we will use to display our information. We will also make this class implement the TreeSelectionListener interface so that it is capable of receiving notification of any tree selection events. The class would look like this:
package softwarepulse.app; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; /** * @author jmcneil * (c) copyright Software Pulse 2018 * */ public class PizzaPanel implements TreeSelectionListener { private JPanel jpanel = new JPanel(); private JLabel info; public PizzaPanel() { super(); initialise(); } private void initialise() { info = new JLabel("Selction shows here..."); jpanel.add(info); } public JPanel getPizzapanel() { return jpanel; } /* (non-Javadoc) * @see javax.swing.event.TreeSelectionListener#valueChanged(javax.swing.event.TreeSelectionEvent) */ @Override public void valueChanged(TreeSelectionEvent tsl) { if (tsl.getNewLeadSelectionPath() != null ) { info.setText(tsl.getNewLeadSelectionPath().getLastPathComponent().toString()); } } }
The valueChanged(TreeSelectionEvent) method checks to see if a node has been selected and if so obtains the object and uses the toString() method to set the text on the JLabel for the display panel.
So in order for our new PizzaPanel class to receive events from our JTree we need to let JTree know we are interested in these events. As we have explained JTree already has a means of notifying objects that are interested so really all we need to do is find a way of telling JTree this object is interested.
For this example we will build a new main class which still has all the same elements from the previous example, albeit moved around somewhat. Our class still extends JFrame but now we use the default constructor to set the on close action, title and layout. We also call a new private method to get the split pane and add it to the frame.
The getSplitPane() method gets the containers for the left and right sides of the split pane, once again calling private methods to do this. The term container is used here because the objects returned contain methods which return the JPanel but are not themselves JPanel objects. Once we have a handle to these containers we would then make a call to get the JTree from the JTreePanelThree object, except the previous version does not support this, so that’s a new method we need to add into that class. We need to get access to the JTree because in order to add our PizzaPanel as a listener for the event we need to call the JTree.addTreeSelectionListener() method.
Once we have added the listener we can then call the getJpanel() method for both containers adding the returned JPanels to the left and right sides of the split pane. Our new main method now creates an instance of the class and displays the frame.
Our code looks like this:
JTree Panel Three class
package softwarepulse.app; import javax.swing.JPanel; import javax.swing.JTree; import javax.swing.tree.DefaultMutableTreeNode; public class JTreePanelThree { private JPanel jpanel = new JPanel(); private JTree treeOne; final String[][] toppings3 = { {"Thick Crust"}, {"Cheese", "Pepperoni", "Black Olives"}, {"Thin Crust"}, {"Ham and Pinapple","Chicken" } } ; public JTreePanelThree() { super(); DefaultMutableTreeNode root = new DefaultMutableTreeNode("root"); DefaultMutableTreeNode sub1 = new DefaultMutableTreeNode(new DefaultMutableTreeNode(toppings3[0][0])); DefaultMutableTreeNode sub2 = new DefaultMutableTreeNode(new DefaultMutableTreeNode(toppings3[2][0])); sub1.add( new DefaultMutableTreeNode(toppings3[1][0]) ); sub1.add( new DefaultMutableTreeNode(toppings3[1][1]) ); sub1.add( new DefaultMutableTreeNode(toppings3[1][2]) ); sub2.add( new DefaultMutableTreeNode(toppings3[3][0]) ); sub2.add( new DefaultMutableTreeNode(toppings3[3][1]) ); root.add(sub1); root.add(sub2); treeOne = new JTree( root ); treeOne.setRootVisible(false); treeOne.setShowsRootHandles(true); jpanel.add(treeOne); } public JPanel getJpanel() { return jpanel; } public JTree getTreeOne() { return treeOne; } }
JTree Example Two class
package softwarepulse.app; import java.awt.BorderLayout; import java.awt.EventQueue; import javax.swing.JFrame; import javax.swing.JSplitPane; /** * @author jmcneil * (c) copyright Software Pulse 2018 * */ public class JTreeExampleTwo extends JFrame { public JTreeExampleTwo() { super(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setTitle("JTree Basic Examples 2"); setLayout(new BorderLayout()); add(getSplitPane(), "Center"); } private JSplitPane getSplitPane() { JTreePanelThree leftPane = getJTreeContainer(); PizzaPanel rightPane = getRightPanelContainer(); leftPane.getTreeOne().addTreeSelectionListener(rightPane); JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPane.getJpanel(), rightPane.getPizzapanel() ); return splitPane; } private JTreePanelThree getJTreeContainer() { JTreePanelThree mytree3 = new JTreePanelThree(); return mytree3; } private PizzaPanel getRightPanelContainer() { return new PizzaPanel(); } /** * @param args */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { JTreeExampleTwo app = new JTreeExampleTwo(); app.setVisible(true); app.pack(); } }); } }
As we can see from this new application, as we select nodes in the JTree the text of the node is displayed in the right hand side panel.
Download the source code for this example here (email address required)