Subpages: 1. JTree
2. Basic JTree example
3. Directories tree: part I - Dynamic node retrieval
4. Directories tree: part II - Popup menus and programmatic navigation
5. Directories tree: part III - Tooltips
6. JTree and XML documents
7. Custom editors and renderers
17.4 Directories tree: part II - popup menus and programmatic navigation
The example in the previous section can be extended in numerous ways to serve as a framework for a much more flexible application. In this section we'll add simple popup menus to our tree, displayed in response to a right mouse click, with content dependant on the click location. (We discussed popup menus in chapter 12.)
Our popup menu either contains an "Expand" or "Collapse" item depending on the status of the corresponding node nearest to the mouse click. These items will programatically invoke an expand or collapse of the given node. Our popup menu also contains "Delete" and "Rename" dummy items that are not completely implemented, but explicitly illustrate how we might continue to build upon this example to create a more complete directory explorer application.

Figure 17.4 Node dependant popup menus allowing programmatic expand and collapse.
<<file figure17-4.gif>>
The Code: FileTree2.java
see \Chapter17\3
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.event.*;
public class FileTree2 extends JFrame
{
// Unchanged code from section 17.3
protected JPopupMenu m_popup;
protected Action m_action;
protected TreePath m_clickedPath;
public FileTree2() {
super("Directories Tree [Popup Menus]");
setSize(400, 300);
getContentPane().setLayout(new BorderLayout());
// Unchanged code from sectionn 17.3
m_popup = new JPopupMenu();
m_action = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
if (m_clickedPath==null)
return;
if (m_tree.isExpanded(m_clickedPath))
m_tree.collapsePath(m_clickedPath);
else
m_tree.expandPath(m_clickedPath);
}
};
m_popup.add(m_action);
m_popup.addSeparator();
Action a1 = new AbstractAction("Delete") {
public void actionPerformed(ActionEvent e) {
m_tree.repaint();
JOptionPane.showMessageDialog(FileTree2.this,
"Delete option is not implemented",
"Info", JOptionPane.INFORMATION_MESSAGE);
}
};
m_popup.add(a1);
Action a2 = new AbstractAction("Rename") {
public void actionPerformed(ActionEvent e) {
m_tree.repaint();
JOptionPane.showMessageDialog(FileTree2.this,
"Rename option is not implemented",
"Info", JOptionPane.INFORMATION_MESSAGE);
}
};
m_popup.add(a2);
m_tree.add(m_popup);
m_tree.addMouseListener(new PopupTrigger());
WindowListener wndCloser = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
};
addWindowListener(wndCloser);
setVisible(true);
}
// Unchanged code from section 17.3
class PopupTrigger extends MouseAdapter {
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
int x = e.getX();
int y = e.getY();
TreePath path = m_tree.getPathForLocation(x, y);
if (path != null) {
if (m_tree.isExpanded(path))
m_action.putValue(Action.NAME, "Collapse");
else
m_action.putValue(Action.NAME, "Expand");
m_popup.show(m_tree, x, y);
m_clickedPath = path;
}
}
}
}
public static void main(String argv[]) {
new FileTree2();
}
}
// Unchanged code from section 17.3
Understanding the Code
Class FileTree2
This example adds three new instance variables:
JPopupMenu m_popup: popup menu component
Action m_action: context sensitive menu action.
TreePath m_clickedPath: most recent tree path corresponding to a mouse click.
New code in the base class constructor creates a popup menu component and populates it with three menu items: "Expand", " Delete", and "Rename". The last two items intentionally just display an "option is not implemented" message. Their true implementations would take us too far into file manipulation techniques for this chapter. The first one, on the contrary, is quite meaningful here. The corresponding actionPerformed() method uses the recently clicked path (not necessary the currently selected path) which has been set by the PopupTrigger instance (see below). This path is collapsed if it currently expanded, or expanded it if this path is currently collapsed.
Finally this newly created popup menu is added to our tree component. An instance of our PopupTrigger class is also attatched to our tree as a mouse listener.
Class FileTree2.PopupTrigger
This class extends MouseAdapter to trigger the display of our popup menu. This menu should be displayed when the right mouse button is released. So we override the mouseReleased() method and check whether isPopupTrigger() is true (see MouseEvent API docs). In this case we determine the coordinates of the click and retrieve the TreePath corresponding to that coordinate with the getPathForLocation() method. If a path is not found (i.e. the click does not occur on a tree node or leaf) we do nothing. Otherwise we adjust the title of the first menu item accordingly, display our popup menu with the show() method, and store our recently clicked path in the m_clickedPath instance variable (for use by the expand/collapse Action as discussed above).
Running the Code
Figure 17.4 shows our directories tree application displaying a context sensitive popup menu. Note how the first menu item is changed depending on whether the selected tree node is collapsed or expanded. Also note that the tree can be manipulated (expanded or collapsed) programmatically by choosing the "Collapse" or "Expand" popup menu item.
UI Guideline : Visually re-inforcing variations in behaviour
If you intend to introduce context dependant pop-up menus on tree cells, then this is an ideal time to consider the use of a tree cell renderer which incorporates an icon. The differing icons help to re-inforce the idea that the data on the cell is of different types and consequently when the behaviour is slightly different across nodes, it is less surprising. The icon visually re-inforces the difference in behaviour.



RSS feed Java FAQ News