0

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());
}
}
Frakcool
  • 10,915
  • 9
  • 50
  • 89
daniel lozano
  • 421
  • 6
  • 19
  • Possible duplicate of [Java Swing: Need a good quality developed JTree with checkboxes](https://stackoverflow.com/questions/21847411/java-swing-need-a-good-quality-developed-jtree-with-checkboxes) – XtremeBaumer Apr 11 '19 at 11:15
  • Do NOT create a checkbox each time in `getTreeCellRendererComponent`! Please read how renderer works. Moreover, use the example you linked yourself and add `editor` to process the clicks, as renderer only draws – igorepst Apr 11 '19 at 11:36
  • thanks @XtremeBaumer. I've already checked and tried the example you are reffering to, but what I am looking for is more simple. I don't want to create a specific class to have a JCheckbox component, with all the classes it needs – daniel lozano Apr 11 '19 at 11:45
  • thanks @igorepst! by creating the checkbox in the `getTreeCellRendererComponent` I can convert the `DefaultMutableTreeNode` to a `JCheckBox`. If I place the `ActionListener` inside each `JCheckBox`, it should be fired only when I change the state of that `JCheckBox`, doesn't it? In my original program, I define items, and types. The types are checkboxes, and items are labels that are leafs of its type. I need to throw this event when I change the state of the checkboxes (the types) so, how I should create the checkboxes for the types if it is not in the `getTreeCellRendererComponent` then? Thx – daniel lozano Apr 11 '19 at 12:49
  • Please read the answer to the question you linked to! Especially `the number of calls to getTreeCellRendererComponent is uncontrollable`. This means you **must not** create anything in this function. It is really right. Just copy the code from the linked question and change it to your liking – igorepst Apr 11 '19 at 13:09
  • Note that the used code is from [external site](http://www.java2s.com/Code/Java/Swing-JFC/CheckBoxNodeTreeSample.htm) – igorepst Apr 11 '19 at 13:10
  • @MebinJoe when you edit a question, be sure to fix all the errors in it, in this case you could also remove the "signature" noise in it as well. Just a tip :) – Frakcool Apr 11 '19 at 21:20
  • thanks @igorepst, now I understand what you mean with **not to create** anything there inside. About the code you're refering, maybe I'm not explaining well my problem. I tried before the example you're refering, and with that example, or I am not able how to do this, or simply not possible. What I need to do is to mix in the same tree labels and checkboxes mixing parents and leafs, and I achieved this with the cellRenderer, but doing it there I am having the problems I specified in the question. Maybe there is a way to do this with the code of the link you're refering? Thank you very much! – daniel lozano Apr 12 '19 at 08:02

0 Answers0