编辑中返回意外值 - JTree
Unexpected value returned in edit - JTree
在下面的代码中有一个例子 JTree
每行有两个 JToggleButtons
和一个 JLabel
都包含在 Holder (subclass of JPanel)
.
此 JTree
上的一片叶子可能如下所示。
并且当 JToggleButtons
之一被点击时,被点击的切换按钮应该改变颜色。但是,输出非常不同,如下所示。
为什么会出现这种情况,我该如何解决这个问题?
注意:这个return值可以在public component getTreeCellEditorComponent(...)
中找到
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import javax.swing.table.*;
import javax.swing.plaf.basic.*;
import javax.swing.plaf.metal.*;
@SuppressWarnings("serial")
public class DirectoryExplorer extends JFrame {
private DirectoryExplorer() {
super("Directory Explorer");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout(1, 1));
createPanel();
setSize(800,600);
setVisible(true);
}
private void createPanel() {
DefaultMutableTreeNode colors = new DefaultMutableTreeNode("Colours");
colors.add(new DefaultMutableTreeNode("Red"));
colors.add(new DefaultMutableTreeNode("Green"));
colors.add(new DefaultMutableTreeNode("Blue"));
DefaultMutableTreeNode falvors = new DefaultMutableTreeNode("Flavours");
falvors.add(new DefaultMutableTreeNode("Toffee"));
falvors.add(new DefaultMutableTreeNode("Fudge"));
falvors.add(new DefaultMutableTreeNode("Chocolate"));
DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
root.add(colors);
root.add(falvors);
root.add(new DefaultMutableTreeNode("Leafy"));
JPanel panel = new JPanel(new GridLayout(1, 1));
JTree tree = new JTree(root);
FileNameRenderer fileRender = new FileNameRenderer();
tree.setCellRenderer(fileRender);
tree.setCellEditor(new CheckBoxNodeEditor(tree));
tree.setEditable(true);
tree.setShowsRootHandles(true);
panel.add(new JScrollPane(tree));
getContentPane().add(panel);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new DirectoryExplorer());
}
private class FileNameRenderer extends DefaultTreeCellRenderer {
private DefaultChkBx def = new DefaultChkBx();
private FavouriteChkBx fav = new FavouriteChkBx();
protected DefaultChkBx getDefBut() {
return def;
}
protected FavouriteChkBx getFavBut() {
return fav;
}
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
JComponent c = (JComponent) super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
return new Holder((JLabel) c, def, fav);
}
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus, boolean defSel, boolean favSel) {
JComponent c = (JComponent) super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
def.setSelected(defSel);
fav.setSelected(favSel);
return new Holder((JLabel) c, def, fav);
}
}
private class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor {
FileNameRenderer renderer = new FileNameRenderer();
ChangeEvent changeEvent = null;
JTree t;
TreePath path;
DefaultChkBx def = renderer.getDefBut();
FavouriteChkBx fav = renderer.getFavBut();
public CheckBoxNodeEditor(JTree tree) {
t = tree;
}
public Object getCellEditorValue() {
def = renderer.getDefBut();
fav = renderer.getFavBut();
def.setSelected(def.isSelected());
fav.setSelected(fav.isSelected());
Holder checkBoxNode = new Holder(new JLabel((((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject().toString())), def, fav);
return checkBoxNode;
}
public boolean isCellEditable(EventObject event) {
if(event instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent) event;
path = t.getPathForLocation(mouseEvent.getX(), mouseEvent.getY());
if (path != null) {
Object node = path.getLastPathComponent();
if ((node != null) && (node instanceof DefaultMutableTreeNode)) {
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) node;
Object userObject = treeNode.getUserObject();
return (userObject instanceof String);
}
}
}
return false;
}
public Component getTreeCellEditorComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row) {
Component editor = renderer.getTreeCellRendererComponent(tree, value, true, expanded, leaf, row, true);
ItemListener itemListener = new ItemListener() {
public void itemStateChanged(ItemEvent itemEvent) {
if (stopCellEditing())
fireEditingStopped();
}
};
if (editor instanceof Holder) {
for(Component c : ((Holder) editor).getComponents()) {
if(c instanceof DefaultChkBx)
((DefaultChkBx) c).addItemListener(itemListener);
else if(c instanceof FavouriteChkBx)
((FavouriteChkBx) c).addItemListener(itemListener);
}
}
return editor;
}
}
private class Holder extends JPanel {
public Holder(Component c, DefaultChkBx def, FavouriteChkBx fav) {
setLayout(new GridBagLayout());
setBackground(Color.BLACK);
setOpaque(false);
addComponents(c, def, fav);
}
private void addComponents(Component c, DefaultChkBx def, FavouriteChkBx fav) {
GridBagConstraints gBC = new GridBagConstraints();
gBC.insets = new Insets(0, 0, 0, 5);
add(c, gBC);
gBC.insets = new Insets(0, 0, 0, 0);
add(def, gBC);
add(fav, gBC);
}
}
private class DefaultChkBx extends JToggleButton {
public DefaultChkBx() {
setUI(new MetalToggleButtonUI() {
@Override
protected Color getSelectColor() {
return new Color(242, 0, 255);
}
});
setBorder(null);
setForeground(Color.GRAY);
setText("Default");
setFocusPainted(false);
}
}
private class FavouriteChkBx extends JToggleButton {
public FavouriteChkBx() {
setUI(new MetalToggleButtonUI() {
@Override
protected Color getSelectColor() {
return Color.RED;
}
});
setBorder(null);
setForeground(Color.GRAY);
setText("Favourite");
setFocusPainted(false);
}
}
}
在 CheckBoxNodeEditor
中,您的 getCellEditorValue()
应该 return 编辑对象的值(通常是叶中显示的 String
对象)。
相反,您的方法 return 是 Holder
的一个实例。 toString()
方法在此对象上调用并由树显示(这是您看到的 "DirectoryExplorer$Holder[....." 显示)。
作为开始,您可以通过此方法return 一个简单的字符串(如 "Leafy")。
在下面的代码中有一个例子 JTree
每行有两个 JToggleButtons
和一个 JLabel
都包含在 Holder (subclass of JPanel)
.
此 JTree
上的一片叶子可能如下所示。
并且当 JToggleButtons
之一被点击时,被点击的切换按钮应该改变颜色。但是,输出非常不同,如下所示。
为什么会出现这种情况,我该如何解决这个问题?
注意:这个return值可以在public component getTreeCellEditorComponent(...)
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import javax.swing.table.*;
import javax.swing.plaf.basic.*;
import javax.swing.plaf.metal.*;
@SuppressWarnings("serial")
public class DirectoryExplorer extends JFrame {
private DirectoryExplorer() {
super("Directory Explorer");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout(1, 1));
createPanel();
setSize(800,600);
setVisible(true);
}
private void createPanel() {
DefaultMutableTreeNode colors = new DefaultMutableTreeNode("Colours");
colors.add(new DefaultMutableTreeNode("Red"));
colors.add(new DefaultMutableTreeNode("Green"));
colors.add(new DefaultMutableTreeNode("Blue"));
DefaultMutableTreeNode falvors = new DefaultMutableTreeNode("Flavours");
falvors.add(new DefaultMutableTreeNode("Toffee"));
falvors.add(new DefaultMutableTreeNode("Fudge"));
falvors.add(new DefaultMutableTreeNode("Chocolate"));
DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
root.add(colors);
root.add(falvors);
root.add(new DefaultMutableTreeNode("Leafy"));
JPanel panel = new JPanel(new GridLayout(1, 1));
JTree tree = new JTree(root);
FileNameRenderer fileRender = new FileNameRenderer();
tree.setCellRenderer(fileRender);
tree.setCellEditor(new CheckBoxNodeEditor(tree));
tree.setEditable(true);
tree.setShowsRootHandles(true);
panel.add(new JScrollPane(tree));
getContentPane().add(panel);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new DirectoryExplorer());
}
private class FileNameRenderer extends DefaultTreeCellRenderer {
private DefaultChkBx def = new DefaultChkBx();
private FavouriteChkBx fav = new FavouriteChkBx();
protected DefaultChkBx getDefBut() {
return def;
}
protected FavouriteChkBx getFavBut() {
return fav;
}
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
JComponent c = (JComponent) super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
return new Holder((JLabel) c, def, fav);
}
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus, boolean defSel, boolean favSel) {
JComponent c = (JComponent) super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
def.setSelected(defSel);
fav.setSelected(favSel);
return new Holder((JLabel) c, def, fav);
}
}
private class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor {
FileNameRenderer renderer = new FileNameRenderer();
ChangeEvent changeEvent = null;
JTree t;
TreePath path;
DefaultChkBx def = renderer.getDefBut();
FavouriteChkBx fav = renderer.getFavBut();
public CheckBoxNodeEditor(JTree tree) {
t = tree;
}
public Object getCellEditorValue() {
def = renderer.getDefBut();
fav = renderer.getFavBut();
def.setSelected(def.isSelected());
fav.setSelected(fav.isSelected());
Holder checkBoxNode = new Holder(new JLabel((((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject().toString())), def, fav);
return checkBoxNode;
}
public boolean isCellEditable(EventObject event) {
if(event instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent) event;
path = t.getPathForLocation(mouseEvent.getX(), mouseEvent.getY());
if (path != null) {
Object node = path.getLastPathComponent();
if ((node != null) && (node instanceof DefaultMutableTreeNode)) {
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) node;
Object userObject = treeNode.getUserObject();
return (userObject instanceof String);
}
}
}
return false;
}
public Component getTreeCellEditorComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row) {
Component editor = renderer.getTreeCellRendererComponent(tree, value, true, expanded, leaf, row, true);
ItemListener itemListener = new ItemListener() {
public void itemStateChanged(ItemEvent itemEvent) {
if (stopCellEditing())
fireEditingStopped();
}
};
if (editor instanceof Holder) {
for(Component c : ((Holder) editor).getComponents()) {
if(c instanceof DefaultChkBx)
((DefaultChkBx) c).addItemListener(itemListener);
else if(c instanceof FavouriteChkBx)
((FavouriteChkBx) c).addItemListener(itemListener);
}
}
return editor;
}
}
private class Holder extends JPanel {
public Holder(Component c, DefaultChkBx def, FavouriteChkBx fav) {
setLayout(new GridBagLayout());
setBackground(Color.BLACK);
setOpaque(false);
addComponents(c, def, fav);
}
private void addComponents(Component c, DefaultChkBx def, FavouriteChkBx fav) {
GridBagConstraints gBC = new GridBagConstraints();
gBC.insets = new Insets(0, 0, 0, 5);
add(c, gBC);
gBC.insets = new Insets(0, 0, 0, 0);
add(def, gBC);
add(fav, gBC);
}
}
private class DefaultChkBx extends JToggleButton {
public DefaultChkBx() {
setUI(new MetalToggleButtonUI() {
@Override
protected Color getSelectColor() {
return new Color(242, 0, 255);
}
});
setBorder(null);
setForeground(Color.GRAY);
setText("Default");
setFocusPainted(false);
}
}
private class FavouriteChkBx extends JToggleButton {
public FavouriteChkBx() {
setUI(new MetalToggleButtonUI() {
@Override
protected Color getSelectColor() {
return Color.RED;
}
});
setBorder(null);
setForeground(Color.GRAY);
setText("Favourite");
setFocusPainted(false);
}
}
}
在 CheckBoxNodeEditor
中,您的 getCellEditorValue()
应该 return 编辑对象的值(通常是叶中显示的 String
对象)。
相反,您的方法 return 是 Holder
的一个实例。 toString()
方法在此对象上调用并由树显示(这是您看到的 "DirectoryExplorer$Holder[....." 显示)。
作为开始,您可以通过此方法return 一个简单的字符串(如 "Leafy")。