单击后防止 JButton repaint()

Prevent JButton repaint() after click

我有一个按钮。我想在点击它后更改背景。我的问题是按钮自动调用 paintComponent()。如何防止这种情况?我希望点击按钮后按钮会是蓝色的,但它仍然是红色的。

package test;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ButtonDemo extends JButton implements ActionListener{

    public ButtonDemo() {
        this.setText("BUTTON TEXT");
        this.addActionListener(this);
    }
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        setBackground(Color.RED);
    }
    public static void main(String[] args){
        JFrame frame = new JFrame();
        JPanel contentPane = new JPanel();
        frame.setContentPane(contentPane);
        contentPane.add(new ButtonDemo());
        frame.setSize(500, 500);

        frame.setVisible(true);

    }
    @Override
    public void actionPerformed(ActionEvent e) {
        this.setBackground(Color.BLUE);
    }  
}

我创建了一个切换按钮。

您在 class 构造函数中设置主色和备用色。

当您调用 switchColors 方法时,JButton 背景从原色变为备用色。当您再次调用 switchColors 方法时,JButton 背景从备用颜色变为主要颜色。

在下面的示例中,我将 switchColors 方法放在 actionListener 中,以便您可以看到颜色变化。每次左键单击 JButton 时,背景颜色都会改变。

当您希望 JButton 背景从蓝色变为红色时调用 switchColors 方法,当您希望 JButton 背景从红色变为蓝色时再次调用.它在你的控制之下。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class ButtonDemo extends JButton 
        implements ActionListener {

    private static final long serialVersionUID = 1L;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("Button Demo");
                frame.setDefaultCloseOperation(
                        JFrame.EXIT_ON_CLOSE);
                JPanel contentPane = new JPanel();
                contentPane.setLayout(new BorderLayout());
                frame.setContentPane(contentPane);
                contentPane.add(new ButtonDemo(Color.BLUE, 
                        Color.RED));
                frame.setSize(300, 300);
                frame.setLocationByPlatform(true);
                frame.setVisible(true);
            }
        });
    }

    private boolean primaryBackground;

    private Color primaryColor;
    private Color alternateColor;

    public ButtonDemo(Color primaryColor, 
            Color alternateColor) {
        this.primaryColor = primaryColor;
        this.alternateColor = alternateColor;
        this.primaryBackground = true;

        this.setText("BUTTON TEXT");
        this.setBackground(primaryColor);
        this.addActionListener(this);
    }

    public void switchColors() {
        primaryBackground = !primaryBackground;
        Color color = primaryBackground ? primaryColor :
            alternateColor;
        this.setBackground(color);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        switchColors();
    }

}

我个人的直觉是 JButton 可能不适合您的预期目标。

本质上,您想要控制片段的 "selected" 状态何时以及如何改变。

就个人而言,我会有某种控制器以某种方式监视鼠标事件(可能让棋子组件将事件委托回控制器)和某种模型来控制棋子何时变为 selected,然后这将通知控制器状态更改,并且它将对 UI.

进行适当的更新

但这是一个漫长的设置过程。相反,我演示了一个简单的概念,其中一个组件可以用鼠标 selected,但只有控制器可以 de-select。在此示例中,这将只允许 selected

单件
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class Main {

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

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new GridLayout(5, 5));

            ChangeListener listener = new ChangeListener() {
                private PiecePane selectedPiece;

                @Override
                public void stateChanged(ChangeEvent e) {
                    if (!(e.getSource() instanceof PiecePane)) { return; }

                    PiecePane piece = (PiecePane) e.getSource();

                    // Want to ignore events from the selected piece, as this
                    // might interfer with the changing of the pieces
                    if (selectedPiece == piece) { return; }

                    if (selectedPiece != null) {
                        selectedPiece.setSelecetd(false);
                        selectedPiece = null;
                    }

                    selectedPiece = piece;
                }
            };

            for (int index = 0; index < 5 * 5; index++) {
                PiecePane pane = new PiecePane();
                pane.addChangeListener(listener);
                add(pane);
            }
        }

    }

    public class PiecePane extends JPanel {

        private boolean selecetd;
        private Color selectedBackground;
        private Color normalBackground;

        private MouseListener mouseListener;

        public PiecePane() {
            setBorder(new LineBorder(Color.DARK_GRAY));
            mouseListener = new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    setSelecetd(true);
                }
            };

            setNormalBackground(Color.BLUE);
            setSelectedBackground(Color.RED);
        }

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

        @Override
        public void addNotify() {
            super.addNotify(); 
            addMouseListener(mouseListener);
        }

        @Override
        public void removeNotify() {
            super.removeNotify(); 
            removeMouseListener(mouseListener);
        }

        public void addChangeListener(ChangeListener listener) {
            listenerList.add(ChangeListener.class, listener);
        }

        public void removeChangeListener(ChangeListener listener) {
            listenerList.remove(ChangeListener.class, listener);
        }

        protected void fireSelectionChanged() {
            ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class);
            if (listeners.length == 0) {
                return;
            }
            ChangeEvent evt = new ChangeEvent(this);
            for (int index = listeners.length - 1; index >= 0; index--) {
                listeners[index].stateChanged(evt);
            }
        }

        public boolean isSelected() {
            return selecetd;
        }

        public void setSelecetd(boolean selecetd) {
            if (selecetd == this.selecetd) { return; }
            this.selecetd = selecetd;
            updateSelectedState();
            fireSelectionChanged();
        }

        public Color getSelectedBackground() {
            return selectedBackground;
        }

        public void setSelectedBackground(Color selectedBackground) {
            this.selectedBackground = selectedBackground;
            updateSelectedState();
        }

        public Color getNormalBackground() {
            return normalBackground;
        }

        public void setNormalBackground(Color normalBackground) {
            this.normalBackground = normalBackground;
            updateSelectedState();
        }

        protected void updateSelectedState() {
            if (isSelected()) {
                setBackground(getSelectedBackground());
            } else {
                setBackground(getNormalBackground());
            }
        }
    }
}

如果您想暂时更改背景,可以使用 swing Timer:

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class ButtonDemo extends JButton implements ActionListener{

    private static final int DELAY = 600; //milliseconds
    private final Timer timer;

    public ButtonDemo() {
        this.setText("BUTTON TEXT");
        this.addActionListener(this);
        Color defaultCloor = getBackground();
        timer = new Timer(DELAY, e-> setBackground(defaultCloor));
        timer.setRepeats(false);
    }

    public static void main(String[] args){
        JFrame frame = new JFrame();
        JPanel contentPane = new JPanel();
        frame.setContentPane(contentPane);
        contentPane.add(new ButtonDemo());
        frame.setSize(300, 200);
        frame.setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        timer.stop();
        this.setBackground(Color.RED);
        timer.start();
    }
}