简体   繁体   中英

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 bellow. It is fine for everything, except on 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); . 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 mouse listener, 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));
        }
    }
});

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

    }

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

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

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

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?

Try this with what you already have:

yourButton.setBorder(null);
yourButton.setContentAreaFilled(false);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM