How to change a JButton color on mouse pressed?
Asked Answered
O

9

19

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));
        }
    }
});
Osbourn answered 31/1, 2013 at 13:44 Comment(6)
Ok, but why are you adding mouse listener on JButton?Absa
To change the color of the button when mouse enters, exits and is pressed. So, to highlight the button on mouse over and etc.Osbourn
But why so many fancy colors?Tiptoe
@Osbourn Have you read the first paragraph of my answer? This clearly explains you why this won't work.Frankpledge
See also this answer.Loredo
+1 @GuillaumePolet ah you are right! I missed, I went straight to the code. I'm using your suggestion and it is working like a charm! Thx :)Osbourn
F
31

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

    }

}
Frankpledge answered 31/1, 2013 at 14:11 Comment(1)
+1 for new Color(3, 59, 90).brighter().brighter(), not joking :-)Derril
D
11
Derril answered 31/1, 2013 at 14:5 Comment(8)
never, don't to use MouseListener for JButton I have never used. But can you tell me why?Tiptoe
all those methods are implemented in ButtonsComponents APIS (JButton throught JMenuItem, to JRadioButton), derived Mouse & Keys Events in ButtonModel, safe, directly, confortly, accesible for all L&Fs (I know two three exceptions, not important themes in L&Fs) :-) dot :-)Derril
+1 too, indeed using ButtonModel is a better way to go. @Che, it's always better to rely on a higher model abstraction such as ButtonModel, than relying on low-level API's such as MouseListener.Frankpledge
@GuillaumePolet +1. But how guys like me will know these things while working. If I am in this situation I will just go for MouseListener and finish my job. My question is, how can/shall I know what is best/better?Tiptoe
@Che answer to your question is in comment by (@GuillaumePolet) higher model abstraction v.s. low-levelDerril
@Derril I have seen that. So you mean to say use all the higher level abstraction classes where ever possible?Tiptoe
So, I'm trying to follow the suggested approach of using changeListener + ButtonModel, but I'm not getting any color change when I press the button. The only time I observe the changes is when I click and drag the mouse outside the button. am I missing something? See the code in the original question under the edit1.Osbourn
@Osbourn I haven't any issue with answer by Guillaume Polet, there is everything that you'll be neededDerril
G
6
public class MyCustomButton extends JButton {
    private Color pressedColor = Color.GREEN;
    private Color rolloverColor = Color.RED;
    private Color normalColor = Color.BLUE;

    public MyCustomButton (String text) {
        super(text);
        setBorderPainted(false);
        setFocusPainted(false);

        setContentAreaFilled(false);
        setOpaque(true);

        setBackground(normalColor);
        setForeground(Color.WHITE);
        setFont(new Font("Tahoma", Font.BOLD, 12));
        setText(text);

        addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent evt) {
                if (getModel().isPressed()) {
                    setBackground(pressedColor);
                } else if (getModel().isRollover()) {
                    setBackground(rolloverColor);
                } else {
                    setBackground(normalColor);
                }
            }
        });
    }
}
Gregoor answered 30/5, 2014 at 16:7 Comment(0)
S
2

In my case, I just wanted a simple background and color switch when the user pressed the button.

Adapted Guillaume Polet's solution:

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;

import javax.swing.ButtonModel;
import javax.swing.JButton;

@SuppressWarnings("serial")
class Button extends JButton {

    private Color pressedForeground = Color.BLACK;
    private Color pressedBackground = Color.WHITE;

    Button() {
        this(null);
    }

    Button(String text) {
        super(text);
        super.setContentAreaFilled(false);
        setForeground(Color.WHITE);
        setBackground(Color.BLACK);
        setFocusPainted(false);
        setBorderPainted(false);
        setFont(new Font("arial", Font.PLAIN, 16));
    }

    @Override
    public void paint(Graphics g) {
        Color oldFg = getForeground();
        Color newFg = oldFg;
        ButtonModel mod = getModel();

        if (mod.isPressed()) {
            newFg = pressedForeground;
            g.setColor(pressedBackground);
        } else {
            g.setColor(getBackground());
        }

        g.fillRect(0, 0, getWidth(), getHeight());
        setForeground(newFg);
        super.paintComponent(g);
        setForeground(oldFg);
    }
}
Sidra answered 4/11, 2018 at 18:19 Comment(0)
P
1

Try this with what you already have:

yourButton.setBorder(null);
yourButton.setContentAreaFilled(false);
Penance answered 23/10, 2017 at 18:5 Comment(0)
M
0

Could be nothing but could try to instead use: Color.PINK, capital letters? Any change when doing that?

Also wouldn't the mousepressed & mouseclicked override each other? mousepressed should react when you press it & clicked when you release the pressing of the mouse

Maurist answered 31/1, 2013 at 13:46 Comment(4)
Could be nothing but could try to instead use: Color.PINK, capital letters? It is nothing. They both represent the exact same Color.Frankpledge
Color.PINK refers to Color.pink internally. Both are same.Tiptoe
Even so, wouldn't the mouseclicked event happen right after the mousepressed event? ==> mouseClicked(MouseEvent) Called just after the user clicks the listened-to component. ==> mousePressed(MouseEvent) Called just after the user presses a mouse button while the cursor is over the listened-to component.Maurist
No, events occurs in the following order: mouse pressed, possibly mouse drag, mouse release and then possibly mouse click (as long as button has not been released, there is no click event)Frankpledge
J
0

Instead of setting the color because that appears not to work you could just try setting the background to a stretchable image file and set that as the background. Might that work?

Julienne answered 23/8, 2013 at 11:50 Comment(0)
C
0

This Works For Me! Try This Bro...

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

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

UIManager.put("Button.select", new Color(3, 59, 90)); //<--- Added ---
//btnSave.setBackground(new Color(3, 59, 90));

btnSave.addMouseListener(new MouseListener() {
    @Override
    public void mouseReleased(MouseEvent e) {
        UIManager.put("Button.select", new Color(3, 59, 90)); //<--- Added ---
        //btnSave.setBackground(new Color(3, 59, 90));
    }

    @Override
    public void mousePressed(MouseEvent e) {
        // it's working :)
        UIManager.put("Button.select", Color.pink); //<--- Added ---
        //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());
    }
});    
Chlorella answered 6/5, 2021 at 6:21 Comment(0)
F
0

Initialize a button

JButton button = new JButton();

Then, on mouse pressed do:

button.setContentAreaFilled(false);
button.setOpaque(true);
button.setBackground(/*Insert Color Here*/);

On mouse released do:

button.setContentAreaFilled(true);
button.setBackground(/*Reset Color Here*/);
Fishmonger answered 15/9, 2021 at 0:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.