当我尝试检查/取消选中其中一个复选框(本示例中的“用户01”节点)时,树会丢失节点:
我的代码是这个例子的改编:http://forums.sun.com/thread.jspa?threadID=5321084&start=13.
而不是像这样在DefaultMutableTreeNode中嵌入JCheckBox:
new DefaultMutableTreeNode(new CheckBoxNode("Accessibility",true));
我认为创建一个从DefaultMutableTreeNode派生的模型节点变得更有意义,我称之为JTreeNode.该类自动将DefaultMutableTreeNode的UserObject设置为JCheckBox. TreeCellRenderer使用类ShowCheckBox属性来确定是否使用JCheckBox或DefaultTreeCellRenderer. JTreeNode是这样使用的:
JTreeNode user01 = new JTreeNode("User 01"); user01.setShowCheckBox(true); user01.setSelected(true);
我相信问题是实现TreeCellEditor的类,特别是在getCellEditorValue()或getTreeCellEditorComponent()方法中.我怀疑该问题与getCellEditorValue()返回DefaultMutableTreeNode的派生,而不是一个更简单的模型实例.
public Object getCellEditorValue() { JCheckBox checkBox = renderer.getCheckBoxRenderer(); JTreeNode node = new JTreeNode(checkBox.getText()); node.setShowCheckBox(true); node.setSelected(checkBox.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 JCheckBox) { ((JCheckBox) editor).addItemListener(itemListener); } return editor; }
这是TreeCellRender的getTreeCellRendererComponent()方法:
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 JCheckBox,attempt to render it so if (((JTreeNode) value).getShowCheckBox()) { String stringValue = tree.convertValueToText(value,selected,false); //set default JCheckBox rendering checkBoxRenderer.setText(stringValue); checkBoxRenderer.setSelected(false); //not checked checkBoxRenderer.setEnabled(tree.isEnabled()); if (selected) { //removed colorization //checkBoxRenderer.setForeground(selectionForeground); //checkBoxRenderer.setBackground(selectionBackground); } else { checkBoxRenderer.setForeground(textForeground); checkBoxRenderer.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 JCheckBox settings to match JTreeNode's settings checkBoxRenderer.setText(node.getText()); checkBoxRenderer.setSelected(node.isSelected()); //} } component = checkBoxRenderer; } //if not,render the default else { component = defaultRenderer.getTreeCellRendererComponent(tree,hasFocus); } return component; }
任何想法都非常感激.
解决方法
我创建了一个模型类(TreeNodeModel)来保存相关的节点数据:key,hasCheckBox,isSelected:
public class TreeNodeModel { int key; String value; boolean isSelected=false; boolean hasCheckBox=false; public TreeNodeModel() { } public TreeNodeModel(int key,String value) { this.key=key; this.value = value; } public TreeNodeModel(int key,String value,boolean hasCheckBox) { this.key=key; this.value = value; this.hasCheckBox = hasCheckBox; } public TreeNodeModel(int key,boolean hasCheckBox,boolean isSelected) { this.key=key; this.value = value; this.hasCheckBox=hasCheckBox; this.isSelected = isSelected; } public boolean isSelected() { return this.isSelected; } public void setSelected(boolean newValue) { this.isSelected = newValue; } public boolean hasCheckBox() { return this.hasCheckBox; } public void setCheckBox(boolean newValue) { this.hasCheckBox=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; } }
我创建了一个TreeCellEditor接口的实现:
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.hasCheckBox; } //if (node) } //if (path) } //if (MouseEvent) return editable; } public Object getCellEditorValue() { JCheckBox checkBox = renderer.getCheckBoxRenderer(); TreeNodeModel model = new TreeNodeModel(editedModel.getKey(),checkBox.getText(),checkBox.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 JCheckBox) { ((JCheckBox) editor).addItemListener(itemListener); } return editor; } }
关键是在getTreeCellEditorComponent()方法中捕获模型,并在getCellEditorValue()方法中使用它的Key.
建树很容易:
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);
最后,确定检查哪些节点是检查模型的节点集合(通过按钮)的问题:
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.hasCheckBox && model.isSelected()) { checked.put(model.getKey(),model.getValue()); } //recurse if (childNode.getChildCount()>0) getChildNodes(childNode); } }