我有一个Java应用程序,它在树中显示用户文件系统。我显示带有复选框,图标和文本的文件夹。为此,我必须为树单元格创建一个自定义组件。该组件是JLabel的子类,包含JCheckBox和JLabel。我编写了自己的渲染器和编辑器来显示和编辑组件。当您第一次进入编辑模式时单击复选框,但不会发生关闭编辑的代码。随后对复选框的所有点击都可正常工作。我做了很多搜索,无法解决这个问题。
这是我的渲染器和编辑器的代码。树已设置为允许编辑,并且设置了渲染器和编辑器。
class MyRenderer implements TreeCellRenderer
{
private CheckBoxPanel m_panel;
public MyRenderer()
{
m_panel = new CheckBoxPanel();
}
@Override
public Component getTreeCellRendererComponent(JTree tree,
Object value,
boolean selected,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
MyState state = (MyState)node.getUserObject();
m_panel.setState(state);
return m_panel;
}
}
class MyEditor extends AbstractCellEditor implements TreeCellEditor
{
private CheckBoxPanel m_panel;
private JCheckBox m_checkbox;
private MyState m_state;
public MyEditor()
{
m_panel = new CheckBoxPanel();
// m_panel.setColor(Color.red);
}
@Override
public Component getTreeCellEditorComponent(JTree tree,
Object value,
boolean isSelected,
boolean expanded,
boolean leaf,
int row) {
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)value;
m_state = (MyState)treeNode.getUserObject();
m_panel.setState(m_state);
m_checkbox = m_panel.getCheckBox();
m_checkbox.addItemListener(new ItemListener()
{
@Override
public void itemStateChanged(ItemEvent e)
{
fireEditingStopped();
m_checkbox.removeItemListener(this);
}
});
return m_panel;
}
@Override
public Object getCellEditorValue()
{
m_state.setSelected(m_checkbox.isSelected());
return m_state;
}
@Override
public boolean isCellEditable(EventObject anEvent)
{
if (anEvent instanceof MouseEvent)
{
return true;
}
return false;
}
}
class CheckBoxPanel extends JPanel
{
private JCheckBox m_checkBox;
private JLabel m_label;
public CheckBoxPanel()
{
m_checkBox = new JCheckBox();
m_checkBox.setBackground(UIManager.getColor("Tree.background"));
m_checkBox.setBorder(null);
m_checkBox.setFocusable(true);
m_label = new JLabel();
m_label.setFont(UIManager.getFont("Tree.font"));
m_label.setFocusable(false);
setOpaque(false);
setLayout(new BorderLayout());
add(m_checkBox, BorderLayout.WEST);
add(m_label, BorderLayout.CENTER);
}
public JCheckBox getCheckBox()
{
return m_checkBox;
}
public void setState(MyState _state)
{
m_label.setText(_state.getText());
m_checkBox.setSelected(_state.isSelected());
}
public void setColor(Color _color)
{
m_label.setForeground(_color);
}
}
class MyState
{
private String m_text;
private boolean m_selected;
public MyState(String _text, boolean _selected)
{
m_text = _text;
m_selected = _selected;
}
public String getText()
{
return m_text;
}
public void setText(String _text)
{
m_text = _text;
}
public boolean isSelected()
{
return m_selected;
}
public void setSelected(boolean _selected)
{
m_selected = _selected;
}
}
答案 0 :(得分:1)
Java 1.6.0_41
:工作正常Java 1.7.0_51
:不能为我点击第一次Java 1.8.0
:工作正常以下是一种可能的实现,以避免Java 1.7.0_51
上的此问题(覆盖TreeCellEditor#isCellEditable(...)
):
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
public final class TreeCellEditorFirstClickTest {
public JComponent makeUI() {
JTree tree = new JTree();
TreeModel model = tree.getModel();
DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
Enumeration e = root.breadthFirstEnumeration();
while (e.hasMoreElements()) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) e.nextElement();
Object o = node.getUserObject();
if (o instanceof String) {
node.setUserObject(new CheckBoxNode((String) o, false));
}
}
tree.setEditable(true);
tree.setCellRenderer(new CheckBoxNodeRenderer());
tree.setCellEditor(new CheckBoxNodeEditor());
tree.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
tree.expandRow(0);
return new JScrollPane(tree);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(new TreeCellEditorFirstClickTest().makeUI());
frame.setSize(320, 240);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class CheckBoxNode {
public final String text;
public final boolean selected;
public CheckBoxNode(String text, boolean selected) {
this.text = text;
this.selected = selected;
}
@Override public String toString() {
return text;
}
}
class CheckBoxNodeRenderer implements TreeCellRenderer {
private DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
private final JCheckBox check = new JCheckBox();
private final JPanel p = new JPanel(new BorderLayout());
public CheckBoxNodeRenderer() {
p.setFocusable(false);
p.setRequestFocusEnabled(false);
p.setOpaque(false);
p.add(check, BorderLayout.WEST);
check.setOpaque(false);
}
@Override public Component getTreeCellRendererComponent(
JTree tree, Object value, boolean selected, boolean expanded,
boolean leaf, int row, boolean hasFocus) {
JLabel l = (JLabel) renderer.getTreeCellRendererComponent(
tree, value, selected, expanded, leaf, row, hasFocus);
if (value instanceof DefaultMutableTreeNode) {
check.setEnabled(tree.isEnabled());
check.setFont(tree.getFont());
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
if (userObject instanceof CheckBoxNode) {
CheckBoxNode node = (CheckBoxNode) userObject;
l.setText(node.text);
check.setSelected(node.selected);
}
p.add(l);
return p;
}
return l;
}
}
class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor {
private DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
private final JCheckBox check = new JCheckBox();
private final JPanel p = new JPanel(new BorderLayout());
private String str = null;
public CheckBoxNodeEditor() {
super();
check.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
stopCellEditing();
}
});
p.setFocusable(false);
p.setRequestFocusEnabled(false);
p.setOpaque(false);
p.add(check, BorderLayout.WEST);
check.setOpaque(false);
}
@Override public Component getTreeCellEditorComponent(
JTree tree, Object value, boolean isSelected, boolean expanded,
boolean leaf, int row) {
JLabel l = (JLabel) renderer.getTreeCellRendererComponent(
tree, value, true, expanded, leaf, row, true);
if (value instanceof DefaultMutableTreeNode) {
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
if (userObject instanceof CheckBoxNode) {
CheckBoxNode node = (CheckBoxNode) userObject;
l.setText(node.text);
check.setSelected(node.selected);
str = node.text;
}
p.add(l);
return p;
}
return l;
}
@Override public Object getCellEditorValue() {
return new CheckBoxNode(str, check.isSelected());
}
////1.6.0_41`: work OK
////1.7.0_51`: not work to first click
////1.8.0`: work OK
//@Override public boolean isCellEditable(EventObject e) {
// if (e instanceof MouseEvent && e.getSource() instanceof JTree) {
// return true;
// }
// return false;
//}
@Override public boolean isCellEditable(EventObject e) {
if (e instanceof MouseEvent && e.getSource() instanceof JTree) {
MouseEvent me = (MouseEvent) e;
JTree tree = (JTree) e.getSource();
TreePath path = tree.getPathForLocation(me.getX(), me.getY());
Rectangle r = tree.getPathBounds(path);
if (r == null) {
return false;
}
Dimension d = check.getPreferredSize();
r.setSize(new Dimension(d.width, r.height));
if (r.contains(me.getX(), me.getY())) {
if (str == null && System.getProperty("java.version").startsWith("1.7.0")) {
System.out.println("XXX: Java 7, only on first run\n" + p.getBounds());
check.setBounds(new Rectangle(0, 0, d.width, r.height));
}
return true;
}
}
return false;
}
}