JColorChooser return 之前选择的颜色

JColorChooser return previously chosen color

我正在 Java 中开发一个简单的绘图应用程序,当我选择一种颜色时,按钮背景会完全改变,但返回的颜色始终是以前的颜色。

例如,如果我选择黑色然后选择蓝色,它会涂成 black.And 如果我在蓝色之后选择另一种颜色,它会涂成蓝色。

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();

}

}

问题在于 ActionListener 的通知顺序。通常,Swing 调用以 LIFO 顺序监听

所以,使用下面的代码,加上一些额外的 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;
        }

    }
}

打印...

Get color
null
Choose color

这意味着首先调用用于 "get" 来自按钮的 selected 颜色的 ActionListener,在实际用于 [=] 的 ActionListener 之前31=] 颜色

一个可能的解决方案是使用 PropertyChangeListener 并在 selectedColor 更改时触发 propertyChanged 事件,例如...

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);
            }
        }

    }
}