使用 JCheckBox 节点渲染 JTree
我正在尝试修改标准 Swing JTree 以混合带有和不带有复选框的节点。这是一个示例:
当我尝试选中/取消选中其中一个复选框(中的“User 01”节点)这个例子),树失去了节点:
我的代码是这个例子的改编: http://forums.sun.com/thread.jspa?threadID=5321084&start=13< /a>.
而不是像这样将 JCheckBox 嵌入到 DefaultMutableTreeNode 中:
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, Object value, boolean selected, boolean expanded, boolean leaf, 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, expanded, leaf, row, 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, value, selected, expanded, leaf, row, hasFocus);
}
return component;
}
非常感谢任何想法。
I am attempting to modify the standard Swing JTree to intermingle nodes with and without checkboxes. This is an example:
When I attempt to check/uncheck one of the checkboxes (the 'User 01' node in this example), the tree loses nodes:
I my code is an adaptation of this example: http://forums.sun.com/thread.jspa?threadID=5321084&start=13.
Instead of embedding a JCheckBox in a DefaultMutableTreeNode like this:
new DefaultMutableTreeNode(new CheckBoxNode("Accessibility", true));
I thought it made more sense to create a model node that derived from the DefaultMutableTreeNode, which I call JTreeNode. This class automatically sets the DefaultMutableTreeNode's UserObject to a JCheckBox. The class' ShowCheckBox property is used by the TreeCellRenderer to determine if the JCheckBox or DefaultTreeCellRenderer is used. The JTreeNode is used like this:
JTreeNode user01 = new JTreeNode("User 01");
user01.setShowCheckBox(true);
user01.setSelected(true);
I believe the problem is with the class that implements the TreeCellEditor, specifically in the getCellEditorValue() or getTreeCellEditorComponent() methods. I suspect the issue has something to with the getCellEditorValue() returning a derivative of the DefaultMutableTreeNode, rather than a simpler model instance.
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;
}
Here is the TreeCellRender's getTreeCellRendererComponent() method:
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, 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, expanded, leaf, row, 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, value, selected, expanded, leaf, row, hasFocus);
}
return component;
}
Any thoughts are greatly appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我能够解决这个问题。
我创建了一个模型类(TreeNodeModel)来保存相关节点数据:key, value, hasCheckBox, isSelected:
I创建了 TreeCellEditor 接口的实现:
关键是在 getTreeCellEditorComponent() 方法中捕获模型并在 getCellEditorValue() 方法中使用其 Key。
构建树很容易:
最后,确定检查哪些节点只需检查模型的节点集合(通过按钮):
I was able to solve the problem.
I created a model class (TreeNodeModel) to hold the relevant node data: key, value, hasCheckBox, isSelected:
I created an implementation of the TreeCellEditor interface:
The key was capturing the model in the getTreeCellEditorComponent() method and using its Key in the getCellEditorValue() method.
Building the tree was easy:
Finally, determining which nodes where checked was a matter of examining the model's node collection (via a button):
以下是一些导致我出现渲染问题的“陷阱”:
TreeCellEditor 可能不会共享传递到
JTree.setCellRenderer()
的 TreeCellRenderer 实例。如果TreeCellEditor.getTreeCellEditorComponent()
返回与树的TreeCellRenderer.getTreeCellRendererComponent()
相同的实例,您最终会遇到渲染问题。您将尝试编辑一个单元格,但渲染器针对 5 个不相关的单元格运行。当编辑器尝试检索 JCheckBox 的状态时,它将从最后呈现的单元格(而不是最后编辑的单元格)获取值,这显然是错误的。使用
TreeCellEditor.getCellEditorValue()
修改单元格的值,而不是直接在复选框上添加鼠标侦听器。仅当值被保存时才会调用此方法。如果您立即对鼠标事件采取行动,则CellEditor.cancelCellEditing()
上的值不会回滚。Here are a few "gotchas" that caused rendering problems for me:
The TreeCellEditor may not share the TreeCellRenderer instance passed into
JTree.setCellRenderer()
. IfTreeCellEditor.getTreeCellEditorComponent()
returns the same instance as the tree'sTreeCellRenderer.getTreeCellRendererComponent()
you will end up with rendering problems. You will try editing one cell, but the renderer is run against 5 unrelated cells. When the editor attempts to retrieve the JCheckBox's state it will get the value from the last rendered cell (as opposed to the last edited cell) which is clearly wrong.Use
TreeCellEditor.getCellEditorValue()
to modify a cell's value, instead of adding mouse listeners directly on the checkbox. This method only gets invoked if the value gets saved. If you act immediately on mouse events the value won't roll back onCellEditor.cancelCellEditing()
.