Search code examples
javaswingjbuttonsetbackground

Prevent JButton repaint() after click


I have a button. I want to change the background after I click on it. My problem here is the button auto call paintComponent(). How can prevent this? I expect after clicking the button the button will be blue, but it will still be red.

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

Solution

  • My personal gut feeling is that JButton is probably not suited to your desired goal.

    Essentially, you want to control when and how the "selected" state of the piece is changed.

    Personally, I would have some kind of controller which monitored the mouse events in some way (probably having the piece component delegate the event back to the controller) and some kind of model which control when pieces become selected, this would then notify the controller of the state change and it would make appropriate updates to the UI.

    But that's a long process to setup. Instead, I'm demonstrating a simple concept where a component can be selected with the mouse, but only the controller can de-select. In this example, this will allow only a single piece to be 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());
                }
            }
        }
    }