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); } }