Search code examples
javaswingjcomboboxitemlistener

JCombobox, object changed only on second click (ItemListener)


i've some issue using listener to JCombobox. I have JCombobox with two CercleItemOption which is a composition of a JLabel and an object CercleSelection extending from JPanel. CercleSelection draws a circle with certain color.

So i'm using ItemListener to support the event. My goal is to print on frame the colored circle corresponding to the selected item.

import javax.swing.*;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import java.awt.*;

public class PanneauSelection extends JPanel {

    private GridBagConstraints grid = new GridBagConstraints();

    public PanneauSelection(){
        super();
        init();
        setVisible(true);
    }

    private void init() {

        LineBorder lb;
        CompoundBorder cb;

        setLayout(new GridBagLayout());
        EmptyBorder eb = new EmptyBorder(5,10,5,10);

        grid.fill = GridBagConstraints.BOTH;
        grid.insets = new Insets(3,3,3,3);

        JLabel[] appLabel = {
                new JLabel("<html>Racc. <br/>Bac/conduite</html>", SwingConstants.CENTER),
                new JLabel("Vanne", SwingConstants.CENTER),
                new JLabel("Pompe", SwingConstants.CENTER),
                new JLabel("Turbine", SwingConstants.CENTER),
        };

        CercleSelection[] appCircle = {
                new CercleSelection(new Color(222, 146, 15)),
                new CercleSelection(Color.BLUE),
                new CercleSelection(new Color(67, 160, 53)),
                new CercleSelection(Color.RED),
        };

        DefaultListCellRenderer dlcr = new DefaultListCellRenderer();
        dlcr.setHorizontalAlignment(DefaultListCellRenderer.CENTER);

        JComboBox<CercleItemOption> optionList = new JComboBox<>();
        optionList.addItem(new CercleItemOption(new JLabel("Coude"), new CercleSelection(Color.cyan)));
        optionList.addItem(new CercleItemOption(new JLabel("Chgt de section"), new CercleSelection(Color.PINK)));
        optionList.setRenderer(dlcr);


        for(int i=0; i<appLabel.length; i++){
            grid.gridy = i;

            //First column
            grid.gridx = 0;
            lb = new LineBorder(appCircle[i].getCouleur(), 2, true);
            cb = new CompoundBorder(lb,eb);
            appLabel[i].setBorder(cb);
            add(appLabel[i], grid);

            //Second column
            grid.gridx = 1;
            appCircle[i].setBorder(eb);
            add(appCircle[i], grid);
        }

        grid.gridy = 4;
        grid.gridx = 0;
        add(optionList, grid);

        grid.gridx = 1;
        add(((CercleItemOption)optionList.getSelectedItem()).getCercle(), grid);

        optionList.addItemListener(itemEvent -> {
            setVisible(false);
            grid.gridx = 1;
            grid.gridy = 4;
            CercleItemOption cs = (CercleItemOption) itemEvent.getItem();
            add(cs.getCercle(), grid);
            revalidate();
            repaint();
            setVisible(true);
        });


        this.setBorder(new EmptyBorder(0,20,0,0));
    }


    public static void main(String[] args){
        JFrame f = new JFrame();
        f.add(new PanneauSelection());
        f.pack();
        f.setLocationRelativeTo(null);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);

    }

}

I expected something like :
"coude" -> [Circle] cyan
"chgt de section" -> [Circle] pink

With my code color doesn't change on the first call of ItemListener, but only on the second one. Finally on second click, i have :
"coude" -> [Circle] pink
"chgt de section" -> [Circle] cyan

CercleItemOption class

    import javax.swing.*;

    public class CercleItemOption {
        private JLabel label;
        private CercleSelection cercle;

        public CercleItemOption(JLabel l, CercleSelection c){
            label = l;
            cercle = c;
        }

        @Override
        public String toString(){
            return label.getText();
        }

        public JLabel getLabel() {
            return label;
        }

        public CercleSelection getCercle() {
            return cercle;
        }
    }

CercleSelection class

import javax.swing.*;
import java.awt.*;

public class CercleSelection extends JPanel {

    public final static int TAILLE = 11;

    Color couleur;

    public CercleSelection(Color c){
        super();
        couleur = c;
        setSize(TAILLE,TAILLE);
        setVisible(true);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(couleur);
        //Draw in the middle
        g.fillOval(TAILLE/2,TAILLE/2,TAILLE,TAILLE);
    }

    public Color getCouleur() {
        return couleur;
    }

}

Thank you in advance for help


Solution

  • For someone who have the same issue, the solution was to remove the existed component and replace it to the new one.

    To get the actual component, i add a new variable.

    Class PanneauSelection :

    private CercleItemOption cercleSelectionne;
    

    init() method :

    
    private void init(){
    
         //...
    
         grid.gridy = 4;
         grid.gridx = 0;
         add(optionList, grid);
         grid.gridx = 1;
         cercleSelectionne = ((CercleItemOption) optionList.getSelectedItem());
         add(cercleSelectionne.getCercle(), grid);
    
         optionList.addItemListener(itemEvent -> {
                    remove(cercleSelectionne.getCercle());
                    grid.gridx = 1;
                    grid.gridy = 4;
                    cercleSelectionne = (CercleItemOption) itemEvent.getItem();
                    add(cercleSelectionne.getCercle(), grid);
                    revalidate();
                    repaint();
         });
    
    }