Search code examples
javaswingmouseeventjbutton

How to change a JButton color on mouse pressed?


I want to have custom colors according to the mouse events (mouse enter, exit, pressed, etc). So to accomplish this, I wrote the code below. It is fine for everything, except in the case of the mouse pressed event, which does nothing.

It only works if I override the color in the UIManager like this UIManager.put("Button.select", Color.red);. The problem with the UIManager is that it will change for all my buttons.

Can anyone tell me what I might be doing wrong or what is the best approach to accomplish what I'm trying to do?

My Code:

final JButton btnSave = new JButton("Save");

btnSave.setForeground(new Color(0, 135, 200).brighter());
btnSave.setHorizontalTextPosition(SwingConstants.CENTER);
btnSave.setBorder(null);
btnSave.setBackground(new Color(3, 59, 90));

btnSave.addMouseListener(new MouseListener() {
    @Override
    public void mouseReleased(MouseEvent e) {
        btnSave.setBackground(new Color(3, 59, 90));
    }

    @Override
    public void mousePressed(MouseEvent e) {
        // Not working :(
        btnSave.setBackground(Color.pink);
    }

    @Override
    public void mouseExited(MouseEvent e) {
        btnSave.setBackground(new Color(3, 59, 90));
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        btnSave.setBackground(new Color(3, 59, 90).brighter());
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        btnSave.setBackground(new Color(3, 59, 90).brighter());
    }
});

Edit1: So, instead of MouseListener, I'm using ChangeListener and ButtonModel as suggested by mKorbel. With this code I'm still not observing any changes on mouse pressed in the button except when I press and drag outside the button. Any thoughts?

btnSave.getModel().addChangeListener(new ChangeListener() {

    @Override
    public void stateChanged(ChangeEvent e) {
        ButtonModel model = (ButtonModel) e.getSource();

        if (model.isRollover()) {
            btnSave.setBackground(new Color(3, 59, 90).brighter());
        } else if (model.isPressed()) {
            btnSave.setBackground(Color.BLACK);
        } else {
            btnSave.setBackground(new Color(3, 59, 90));
        }
    }
});

Solution

  • The problem is caused by the fact that a JButton has its content area filled by default and that the Metal L&F will automatically fill it with its internal chosen color when button is pressed.

    Best thing to do, is to extend JButton to create your own button, disable content area filled, and paint yourself the background of the button.

    Here is a small demo for that (not sure it works on other L&F, even pretty sure it does not):

    import java.awt.Color;
    import java.awt.Graphics;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.SwingConstants;
    import javax.swing.SwingUtilities;
    
    public class TestButton {
    
        class MyButton extends JButton {
    
            private Color hoverBackgroundColor;
            private Color pressedBackgroundColor;
    
            public MyButton() {
                this(null);
            }
    
            public MyButton(String text) {
                super(text);
                super.setContentAreaFilled(false);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                if (getModel().isPressed()) {
                    g.setColor(pressedBackgroundColor);
                } else if (getModel().isRollover()) {
                    g.setColor(hoverBackgroundColor);
                } else {
                    g.setColor(getBackground());
                }
                g.fillRect(0, 0, getWidth(), getHeight());
                super.paintComponent(g);
            }
    
            @Override
            public void setContentAreaFilled(boolean b) {
            }
    
            public Color getHoverBackgroundColor() {
                return hoverBackgroundColor;
            }
    
            public void setHoverBackgroundColor(Color hoverBackgroundColor) {
                this.hoverBackgroundColor = hoverBackgroundColor;
            }
    
            public Color getPressedBackgroundColor() {
                return pressedBackgroundColor;
            }
    
            public void setPressedBackgroundColor(Color pressedBackgroundColor) {
                this.pressedBackgroundColor = pressedBackgroundColor;
            }
        }
    
        protected void createAndShowGUI() {
            JFrame frame = new JFrame("Test button");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            final MyButton btnSave = new MyButton("Save");
            btnSave.setForeground(new Color(0, 135, 200).brighter());
            btnSave.setHorizontalTextPosition(SwingConstants.CENTER);
            btnSave.setBorder(null);
            btnSave.setBackground(new Color(3, 59, 90));
            btnSave.setHoverBackgroundColor(new Color(3, 59, 90).brighter());
            btnSave.setPressedBackgroundColor(Color.PINK);
            frame.add(btnSave);
            frame.setSize(200, 200);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new TestButton().createAndShowGUI();
                }
            });
    
        }
    
    }