In the code below there is an example JTree
that has two JToggleButtons
on each row and a JLabel
all contained in a Holder (subclass of JPanel)
.
A leaf on this JTree
might look like the following.
And when one of the JToggleButtons
are clicked, the clicked toggle button should change color. However, the output is very much different, as seen below.
Why is this occurring and how can I fix the problem?
Note: This return value can be found in 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);
}
}
}