Java – JTree rendering and jcheckbox node
I'm trying to modify the standard swing JTree to mix nodes with and without checkboxes Here is an example:
When I try to check / uncheck one of the check boxes (user 01 node in this example), the tree loses nodes:
My code is an adaptation of this example: http://forums.sun.com/thread.jspa?threadID=5321084&start=13.
Instead of embedding in the defaultmutabletreenode like this JCheck@R_941_2419 @:
new DefaultMutableTreeNode(new Check@R_941_2419@Node("Accessibility",true));
I think it makes more sense to create a model node derived from defaultmutabletreenode, which I call jtreenode This class automatically sets the userobject of defaultmutabletreenode to JCheck@R_941_2419 @. treecellrenderer use class ShowCheck@R_941_2419 @Property to determine whether to use JCheck@R_941_2419 @Or defaulttreecellrenderer Jtreenode is used as follows:
JTreeNode user01 = new JTreeNode("User 01");
user01.setShowCheck@R_941_2419@(true);
user01.setSelected(true);
I believe the problem is the class that implements treecelleditor, especially in the getcelleditorvalue () or gettreecelleeditorcomponent () methods I suspect that this problem is related to the derivation of defaultmutabletreenode returned by getcelleditorvalue(), rather than a simpler model instance
public Object getCellEditorValue() {
JCheck@R_941_2419@ check@R_941_2419@ = renderer.getCheck@R_941_2419@Renderer();
JTreeNode node = new JTreeNode(check@R_941_2419@.getText());
node.setShowCheck@R_941_2419@(true);
node.setSelected(check@R_941_2419@.isSelected());
return node;
}
public Component getTreeCellEditorComponent(JTree tree,Object value,boolean isSelected,boolean expanded,boolean leaf,int row) {
Component editor = renderer.getTreeCellRendererComponent(tree,value,true,expanded,leaf,row,true);
// editor always selected / focused
ItemListener itemListener = new ItemListener() {
public void itemStateChanged(ItemEvent itemEvent) {
if (stopCellEditing()) {
fireEditingStopped();
}
}
};
if (editor instanceof JCheck@R_941_2419@) {
((JCheck@R_941_2419@) editor).addItemListener(itemListener);
}
return editor;
}
This is the gettreecellrendercomponent() method of treecellrender:
public Component getTreeCellRendererComponent(JTree tree,boolean selected,int row,boolean hasFocus) {
Component component;
//if object being passed for rendering is a JTreeNode that should show a JCheck@R_941_2419@,attempt to render it so
if (((JTreeNode) value).getShowCheck@R_941_2419@()) {
String stringValue = tree.convertValueToText(value,selected,false);
//set default JCheck@R_941_2419@ rendering
check@R_941_2419@Renderer.setText(stringValue);
check@R_941_2419@Renderer.setSelected(false); //not checked
check@R_941_2419@Renderer.setEnabled(tree.isEnabled());
if (selected) {
//removed colorization
//check@R_941_2419@Renderer.setForeground(selectionForeground);
//check@R_941_2419@Renderer.setBackground(selectionBackground);
}
else {
check@R_941_2419@Renderer.setForeground(textForeground);
check@R_941_2419@Renderer.setBackground(textBackground);
}
//DefaultMutableTreeNode
if ((value != null) && (value instanceof JTreeNode)) {
//userObject should be a JTreeNode instance
//DefaultMutableTreeNode
//Object userObject = ((JTreeNode) value).getUserObject();
//if it is
//if (userObject instanceof JTreeNode) {
//cast as a JTreeNode
//JTreeNode node = (JTreeNode) userObject;
JTreeNode node = (JTreeNode) value;
//set JCheck@R_941_2419@ settings to match JTreeNode's settings
check@R_941_2419@Renderer.setText(node.getText());
check@R_941_2419@Renderer.setSelected(node.isSelected());
//}
}
component = check@R_941_2419@Renderer;
}
//if not,render the default
else {
component = defaultRenderer.getTreeCellRendererComponent(tree,hasFocus);
}
return component;
}
Any idea would be appreciated
Solution
I can solve the problem
I created a model class (treenodermodel) to save the relevant node data: key, hasCheck@R_941_2419 @,isSelected:
public class TreeNodeModel {
int key;
String value;
boolean isSelected=false;
boolean hasCheck@R_941_2419@=false;
public TreeNodeModel() {
}
public TreeNodeModel(int key,String value) {
this.key=key;
this.value = value;
}
public TreeNodeModel(int key,String value,boolean hasCheck@R_941_2419@) {
this.key=key;
this.value = value;
this.hasCheck@R_941_2419@ = hasCheck@R_941_2419@;
}
public TreeNodeModel(int key,boolean hasCheck@R_941_2419@,boolean isSelected) {
this.key=key;
this.value = value;
this.hasCheck@R_941_2419@=hasCheck@R_941_2419@;
this.isSelected = isSelected;
}
public boolean isSelected() {
return this.isSelected;
}
public void setSelected(boolean newValue) {
this.isSelected = newValue;
}
public boolean hasCheck@R_941_2419@() {
return this.hasCheck@R_941_2419@;
}
public void setCheck@R_941_2419@(boolean newValue) {
this.hasCheck@R_941_2419@=newValue;
}
public int getKey() {
return this.key;
}
public void setKey(int newValue) {
this.key = newValue;
}
public String getValue() {
return this.value;
}
public void setValue(String newValue) {
this.value = newValue;
}
@Override
public String toString() {
return getClass().getName() + "[" + this.value + "/" + this.isSelected + "]";
// return this.text;
}
}
I created an implementation of treecelleditor interface:
public class TreeNodeEditor extends AbstractCellEditor implements TreeCellEditor {
private JTree tree;
private TreeNodeModel editedModel = null;
TreeNodeRenderer renderer = new TreeNodeRenderer();
public TreeNodeEditor(JTree tree) {
this.tree=tree;
}
@Override
public boolean isCellEditable(EventObject event) {
boolean editable=false;
if (event instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent) event;
TreePath path = tree.getPathForLocation(mouseEvent.getX(),mouseEvent.getY());
if (path != null) {
Object node = path.getLastPathComponent();
if ((node != null) && (node instanceof DefaultMutableTreeNode)) {
DefaultMutableTreeNode editedNode = (DefaultMutableTreeNode) node;
TreeNodeModel model = (TreeNodeModel) editedNode.getUserObject();
editable = model.hasCheck@R_941_2419@;
} //if (node)
} //if (path)
} //if (MouseEvent)
return editable;
}
public Object getCellEditorValue() {
JCheck@R_941_2419@ check@R_941_2419@ = renderer.getCheck@R_941_2419@Renderer();
TreeNodeModel model = new TreeNodeModel(editedModel.getKey(),check@R_941_2419@.getText(),check@R_941_2419@.isSelected());
return model;
}
public Component getTreeCellEditorComponent(JTree tree,int row) {
if (((DefaultMutableTreeNode) value).getUserObject() instanceof TreeNodeModel) {
editedModel = (TreeNodeModel) ((DefaultMutableTreeNode) value).getUserObject();
}
Component editor = renderer.getTreeCellRendererComponent(tree,true);
// editor always selected / focused
ItemListener itemListener = new ItemListener() {
public void itemStateChanged(ItemEvent itemEvent) {
if (stopCellEditing())
fireEditingStopped();
}
};
if (editor instanceof JCheck@R_941_2419@) {
((JCheck@R_941_2419@) editor).addItemListener(itemListener);
}
return editor;
}
}
The key is to capture the model in the gettreecelleditorcomponent () method and use its key in the getcelleditorvalue () method
It's easy to build:
DefaultMutableTreeNode server = new DefaultMutableTreeNode(new TreeNodeModel(0,"Server 01",false));
DefaultMutableTreeNode userFolder = new DefaultMutableTreeNode(new TreeNodeModel(1,"User Folders",false));
server.add(userFolder);
DefaultMutableTreeNode user01 = new DefaultMutableTreeNode(new TreeNodeModel(2,"User 01",true));
userFolder.add(user01);
DefaultMutableTreeNode clientA = new DefaultMutableTreeNode(new TreeNodeModel(3,"Client A",true));
user01.add(clientA);
DefaultMutableTreeNode clientB = new DefaultMutableTreeNode(new TreeNodeModel(4,"Client B",true));
user01.add(clientB);
DefaultMutableTreeNode publicFolder = new DefaultMutableTreeNode(new TreeNodeModel(5,"Public Folders",false));
server.add(publicFolder);
DefaultMutableTreeNode clientC = new DefaultMutableTreeNode(new TreeNodeModel(6,"Client C",true));
publicFolder.add(clientC);
Tree_Nodes.setCellRenderer(new TreeNodeRenderer());
Tree_Nodes.setCellEditor(new TreeNodeEditor(Tree_Nodes));
Tree_Nodes.setModel(new DefaultTreeModel(server);
Finally, determine which nodes to check are the problem of checking the node set of the model (through the button):
private Map<Integer,String> checked = new HashMap<Integer,String>();
private void Button_CheckedActionPerformed(java.awt.event.ActionEvent evt) {
DefaultTableModel tableModel = ((DefaultTableModel) Table_Nodes.getModel());
tableModel.getDataVector().removeAllElements();
tableModel.fireTableDataChanged();
checked.clear();
DefaultTreeModel treeModel = (DefaultTreeModel) Tree_Nodes.getModel();
DefaultMutableTreeNode root = (DefaultMutableTreeNode) treeModel.getRoot();
getChildNodes(root);
for (Iterator it=checked.entrySet().iterator(); it.hasNext(); ) {
Map.Entry entry = (Map.Entry)it.next();
tableModel.addRow(new Object[] {entry.getKey(),entry.getValue()});
}
Button_Checked.requestFocus();
}
private void getChildNodes(DefaultMutableTreeNode parentNode) {
for (Enumeration e=parentNode.children(); e.hasMoreElements();) {
DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) e.nextElement();
TreeNodeModel model = (TreeNodeModel) childNode.getUserObject();
if (model.hasCheck@R_941_2419@ && model.isSelected()) {
checked.put(model.getKey(),model.getValue());
}
//recurse
if (childNode.getChildCount()>0) getChildNodes(childNode);
}
}
