- The Tree Control
- Tree Appearance
- The TreeNode Interface
- The MutableTreeNode Interface
- The DefaultMutableTreeNode Class
- The TreePath Class
- What is a Leaf?
- Tree Expansion and Traversal
- Expanding and Collapsing Nodes under Program Control
- Tree Expansion Events
- Making Nodes Visible
- Controlling Node Expansion and Collapse
- Tree Model Events
- Implementation Plan for the File System Control
- File System Tree Control Implementation
- Using the File System Tree Control
- Custom Tree Rendering and Editing
- Customizing the Default Tree Cell Renderer
- ToolTips and Renderers
- Custom Cell Editors
- Controlling Which Nodes Can Be Edited
- Controlling Editability by Subclassing JTree
- Programmatic Control of Editors
- Editing Trees with Custom User Objects
- The valueForPathChanged Method
- The Tree Implementation
- The Cell Editor
- The Cell Renderer
- Summary
Custom Cell Editors
If you allow your tree to be edited, it is up to you to carry out whatever action is implied by the change and to check that the new value is legal. One way to make it easier to get legal input values is to supply a custom editor that only offers the legal values, such as a JComboBox. A custom editor must implement the TreeCellEditor interface:
public interface TreeCellEditor extends CellEditor { public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row); }
The TreeCellEditor interface extends CellEditor, which contains methods that are also used to create editable tables, as you'll see later in the next chapter. The getTreeCellEditorComponent method returns a component that can edit a value in the tree; the initial value is passed as the second argument, along with three arguments that specify whether the node being edited is selected or expanded and whether it is a leaf. The last argument gives the screen row of the node. There is only one TreeCellEditor for each tree. As the user edits different nodes, this method is called with different values and may, if necessary, return a differently configured component. Typically, the appearance of the returned component depends on the three boolean arguments, because it occupies the same space in the tree as a cell renderer and therefore may need to draw an appropriate icon (e.g., an open or closed folder).
The methods shared with editors and used with JTable (see Chapter 11, "The Table Control") are as follows:
public interface CellEditor { public Object getCellEditorValue(); public boolean isCellEditable(EventObject); public boolean shouldSelectCell(EventObject); public boolean stopCellEditing(); public void cancelCellEditing(); public void addCellEditorListener( CellEditorListener); public void removeCellEditorListener( CellEditorListener); }
These methods all deal with the mechanics of setting up an editor and starting and stopping the editing process. You don't need to implement all seven of these methods to change the text-based node editor, because most of the work is done for you in the DefaultCellEditor class that provides a complete implementation of an editor that can appear as either a text field, a checkbox, or a combo box. Here are its three constructors:
public DefaultCellEditor(JTextField text); public DefaultCellEditor(JCheckBox box); public DefaultCellEditor(JComboBox combo);
To install a custom editor in a tree, you need to first create the editor (usually by using or subclassing DefaultCellEditor), wrap it in an instance of the DefaultTreeCellEditor class, and then finally call the JTree set-CellEditor method. Two classes are used rather than one because DefaultCellEditor is a generic class that can provide editors suitable for use with both JTree or JTable, while DefaultTreeCellEditor augments any CellEditor to provide the semantics appropriate for editing in a tree.
To add a combo-box editor to a tree requires only a few lines of code. The ComboTree example, that you can run with the command:
java JFCBook.Chapter10.ComboTree
was created by adding the following to the EditableTree program:
t.setEditable(true); final String[] values = { "Mercury", "Gemini", "Apollo", "Skylab", "Shuttle" }; JComboBox combo = new JComboBox(); for (int i = 0 ; i < values.length; i++) { combo.addItem(values[i]); } DefaultTreeCellEditor editor = new DefaultTreeCellEditor( t, dtcr, new DefaultCellEditor(combo)); t.setCellEditor(editor); t.getModel().addTreeModelListener( new TreeModelListener() {
Because the DefaultCellEditor and DefaultTreeCellEditor classes do all of the work, all you need to do is populate the combo box that will appear in the tree and then create the DefaultCellEditor and DefaultTreeCellEditor classes that will manage it. The default cell editor is replaced by calling the JTree method setCellEditor. If you run this example and use one of the standard editing gestures on the Apollo node, the combo box appears, as shown in Figure 1014. Click on the arrow and the list of possible values drops down. When you select one, the drop-down closes and the editor disappears. As with the text editor, selecting a new value causes a TreeModelEvent that contains the new value.
The result will be something like that shown in Figure 1014. The DefaultTreeCellEditor class has two constructors:
public DefaultTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer) public DefaultTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer, TreeCellEditor editor)
Figure 1014 A tree with a Combo Box cell editor
The first constructor installs a new editor that is based on a text field and is the one used when the tree installs its own default editor. If you want to use a custom editor, you will need to use the second constructor and pass your editor as the third argument, as shown in the code extract above. The second argument of both constructors is a DefaultTreeCellRendererwhy is this required when installing a custom editor? When editing starts, the tree will add the editing component to the tree in place of the tree's node. In most cases, however, you would not want to lose the node's icon if it has one. To make sure that the rest of the node is displayed as it is when there is no edit in progress, you need to pass a reference to the tree's renderer to the constructor. If you supply null, the editor will still be installed but the icon will disappear until the edit is completed.