I have a JTree
, with a CustomTreeCellRenderer
, where I change the representation of the nodes by JCheckBoxes. Everything works until here.
Now, in my CustomTreeCellRenderer
, when I define the JCheckBox
that is going to be returned, I set the ActionListener
for each one of them.
In the ActionListener
, I only print the name of the JCheckBox
, just to see if the event is fired or not.
My problem is the following: When I click on a checkbox to change the state, the ActionListener
event is never fired, so the name of the JCheckBox
clicked is never displayed. I think I am not doing anything strange here, so I am not capable to see why the ActionListener
is not fired. It could be because the checkboxes are inside of a JTree
and I have to do something more to make it works? I used listeners in checkboxes before, but not inside trees, and I had not to do nothing special...
Also I've seen that using ItemListener
and ChangeListener
instead of ActionListener
to my checkboxes the event fires many times, and that is not the behaviour I want. I've searched about this multiple event fires when using this two listeners and I've found this:
Multiple ITEM_STATE_CHANGED events from jcheckbox in jtree
I just want to throw the event once, using the ActionListener
, I think it is because of the JTree
, but I can't find the reason why it is not fired.
If it is possible to do this using ItemListener
or ChangeListener
but throwing the event just once, it could be good for me too.
Here is the code (I tried to simplify this as much I could):
Main class:
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class MainItemListener {
public static void main(String[] args){
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JTree tree = new JTree();
//Define the root node
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root Node", true);
//Define the child nodes and add it to the root node
for (int i = 0; i < 3; i++){
DefaultMutableTreeNode childNode = new DefaultMutableTreeNode("Child " + i, false);
root.add(childNode);
}
//Set the tree model
DefaultTreeModel treeModel = new DefaultTreeModel(root);
tree.setModel(treeModel);
//Set my custom tree cell renderer
tree.setCellRenderer(new CustomTreeCellRenderer());
//Set the frame
frame.setSize(800,600);
frame.setVisible(true);
frame.setLayout(new BorderLayout());
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); // Close the application when closing the window
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent aEvent) {
System.exit(0); //Close Application
}
});
panel.add(tree, BorderLayout.CENTER);
frame.add(panel);
}
}
CustomTreeCellRenderer:
import javax.swing.*;
import javax.swing.tree.DefaultTreeCellRenderer;
import java.awt.*;
public class CustomTreeCellRenderer extends DefaultTreeCellRenderer {
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean sel, boolean exp, boolean leaf, int row, boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, sel, exp, leaf, row, hasFocus);
//Convert each node to a JCheckBox and return the JCheckBox
JCheckBox checkBox = new JCheckBox();
checkBox.setOpaque(true);
checkBox.setSelected(sel);
checkBox.setText(value.toString());
//Set the ActionListener to each JCheckBox
checkBox.addActionListener(new ActionListenerSample());
return checkBox;
}
}
ActionListenerExample:
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ActionListenerSample implements ActionListener {
//Just print the name of the JCheckBox to see how this event is fired
@Override
public void actionPerformed(ActionEvent e) {
JCheckBox component = (JCheckBox) e.getSource();
System.out.println(component.getText());
}
}