edaddou
edaddou

Reputation: 39

JColorChooser return previously chosen color

I am working on a simple paint app in Java, when I choose a color the button background changes perfectly, but the returned color is always the previous one.

For example, if I choose black then blue, it will paint in black.And if I choose another color after blue it will paint in Blue.

public class ColorChooserBtn extends JButton {

    private Color color;

    public ColorChooserBtn() {
        super();
        this.setBackground(Color.BLACK);
        this.setPreferredSize(new Dimension(16, 16));
        this.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                Color c = JColorChooser.showDialog(null, "Choose a Color", color);
                if (c != null){
                    setSelectedColor(c);
                    setBackground(color);
                }

           }
       });
    }
    public Color getSelectedColor() {
        return color;
    }

    public void setSelectedColor(Color newColor) {
        color = newColor;
    }

}

public class Paint {
DrawArea drawArea;
JButton  clearBtn;
ColorChooserBtn colorBtn;
ActionListener actionListener = new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == clearBtn){
            drawArea.clear();
        } else if(e.getSource() == colorBtn){
            drawArea.coloring(colorBtn.getSelectedColor());
        }

    }
};

public Paint() {
    JFrame frame =  new JFrame("Paint");
    frame.getContentPane().setLayout(new BorderLayout());
    drawArea = new DrawArea();
    frame.getContentPane().add(drawArea, BorderLayout.CENTER);
    JPanel controls = new JPanel();
    clearBtn = new JButton("Clear");
    clearBtn.addActionListener(actionListener);
    colorBtn =  new ColorChooserBtn();
    colorBtn.addActionListener(actionListener);

    controls.add(clearBtn);
    controls.add(colorBtn);

    frame.getContentPane().add(controls,BorderLayout.NORTH);
    frame.setSize(600, 600);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
}
public static void main(String[] args) {

    new Paint();

}

}

Upvotes: 0

Views: 666

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347184

The problem is the order in which the ActionListener's are notified. Generally, Swing calls listens in LIFO order

So, using the following code, with some additional System.outs...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            ColorChooserBtn btn = new ColorChooserBtn();
            add(btn);
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    System.out.println("Get color");
                    System.out.println(btn.getSelectedColor());
                }
            });
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

    public class ColorChooserBtn extends JButton {

        private Color color;

        public ColorChooserBtn() {
            super();
            this.setBackground(Color.BLACK);
            this.setPreferredSize(new Dimension(16, 16));
            this.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    System.out.println("Choose color");
                    Color c = JColorChooser.showDialog(null, "Choose a Color", color);
                    if (c != null) {
                        setSelectedColor(c);
                        setBackground(color);
                    }
                }
            });
        }

        public Color getSelectedColor() {
            return color;
        }

        public void setSelectedColor(Color newColor) {
            color = newColor;
        }

    }
}

prints...

Get color
null
Choose color

This means that the ActionListener used to "get" the selected color from the button is called first, before the ActionListener which is used to actually select the color

One, possible, solution might be to use a PropertyChangeListener and trigger a propertyChanged event when the selectedColor is changed, for example...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            ColorChooserBtn btn = new ColorChooserBtn();
            add(btn);
            btn.addPropertyChangeListener("selectedColor", new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    System.out.println("Changed");
                    System.out.println(evt.getNewValue());
                }
            });
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

    public class ColorChooserBtn extends JButton {

        private Color color;

        public ColorChooserBtn() {
            super();
            this.setBackground(Color.BLACK);
            this.setPreferredSize(new Dimension(16, 16));
            this.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    System.out.println("Choose color");
                    Color c = JColorChooser.showDialog(null, "Choose a Color", color);
                    if (c != null) {
                        setSelectedColor(c);
                        setBackground(color);
                    }
                }
            });
        }

        public Color getSelectedColor() {
            return color;
        }

        public void setSelectedColor(Color newColor) {
            if (newColor != color) {
                Color oldColor = color;
                color = newColor;
                firePropertyChange("selectedColor", oldColor, newColor);
            }
        }

    }
}

Upvotes: 1

Related Questions