【问题标题】:Prevent JButton repaint() after click单击后防止 JButton repaint()
【发布时间】:2020-08-09 12:53:39
【问题描述】:

我有一个按钮。我想在点击后更改背景。我的问题是按钮自动呼叫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);
    }  
}

【问题讨论】:

  • 所以,基本上,你想要一个“切换”按钮——也许从看看How to Use Buttons, Check Boxes, and Radio Buttons开始,我会密切关注JToggleButton。如果这不是您想要的,那么您可能需要研究构建自己的ButtonModel
  • @MadProgrammer 我正在为象棋人使用按钮。我在paintComponent 中打电话给setBackground。当我单击一个国际象棋人时,我想将背景颜色更改为红色(如提示),然后,我调用 repaint() 来获取默认颜色。你对我有什么建议吗?
  • 请参阅:Are expletives (cursing, swear words or vulgar language) allowed on SE sites?,了解 Stack Overflow 的/Stack Exchange 的政策。保持措辞专业。
  • @Puskin 我认为 JButton 可能不是正确的选择,但我正在寻找一种解决方案,我可以设置 border 属性来代替
  • @Puskin " 我在 paintComponent 中调用 setBackground" - 啊,不 - 不要在 paintComponent 中修改组件的状态

标签: java swing jbutton setbackground


【解决方案1】:

我创建了一个切换按钮。

您在类构造函数中设置原色和备用颜色。

当您调用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();
    }

}

【讨论】:

  • 我必须为我的按钮覆盖paintComponent()。我只希望我的 Button 在单击时改变颜色,然后,我调用 repaint() 并获得红色
  • @Puskin:你没有在你的问题中提到这一点。引用,“我想在点击后更改背景。”这就是我的答案代码的作用。
  • 我正在为象棋人使用按钮。我在paintComponent 中调用setBackground 当我点击一个象棋人时,我想将背景颜色更改为红色(如提示),然后我调用repaint() 来获取默认颜色。你对我有什么建议吗?
  • @Puskin:我在你的评论中不明白的是“在那之后”。编辑您的问题以准确描述将按钮变为红色然后变为蓝色的事件顺序。可能,这一序列发生得如此之快,以至于没有人看到它。
  • 没错。我想在我点击后阻止 repaint() 。所以我的按钮可以保持红色,直到我调用 repaint()
【解决方案2】:

我个人的直觉是JButton 可能不适合你想要的目标。

本质上,您想要控制何时以及如何更改作品的“选定”状态。

就我个人而言,我会有某种控制器以某种方式监视鼠标事件(可能让片段组件将事件委托给控制器)​​和某种模型来控制何时选择片段,然后通知状态更改的控制器,它将对 UI 进行适当的更新。

但这是一个漫长的设置过程。相反,我展示了一个简单的概念,其中可以使用鼠标选择组件,但只有控制器可以取消选择。在这个例子中,这将只允许选择一个单件

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

【讨论】:

  • 错字:public void setSelecetd(boolean selecetd)
  • 谢谢,我还是用按钮,我解决了这个问题,不再调用```repaint()``,而是调用一个内容相同的自写方法。这样可以避免 Swing 的绘画层问题(不完全理解的问题)。
【解决方案3】:

如果你想在短时间内改变背景,可以使用 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();
    }
}

【讨论】:

  • 谢谢,但我希望它不是一个特定的时间,而是在我的控制之下,当我做其他事情时它会恢复到原来的颜色。
猜你喜欢
  • 2013-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-08
  • 1970-01-01
  • 1970-01-01
  • 2022-06-30
  • 1970-01-01
相关资源
最近更新 更多