5

Any JButton that is pressed will seem to "highlight" itself when pressed like so:

Pressed button

I can't seem to find any way of disabling this.

Sandeep Chatterjee
  • 3,220
  • 9
  • 31
  • 47
Fraser Price
  • 899
  • 6
  • 15
  • 36

4 Answers4

7

There are a number of ways you might achieve this...

You Could...

Override paintComponent and implement you own paint logic. This is kind of dangerous and now means that for each state change you want to modify will either require a new JButton based class or some other serious of flags to implement. It's also possible that this could effect other look and feels...

You Could...

Create your own ButtonUI, which would normally be the preferred way, but it's not an insignificant amount of work and you'd need one for each platform you wanted to support

You Could...

Use the icon property of the button to "simulate" the button boundaries. This is preferred solution (over customising the the painting process) as it's easy to apply and doesn't require a specialised button to achieve. It also overcomes some of the issues of how buttons are painted across different platforms (as not all buttons use the background color property the same)

You Could...

Define your own ButtonModel which could ignore certain state changes (like pressed or rollover).

This is a preferred solution as it works with the current look and feel to achieve your results.

FixState

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.DefaultButtonModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class TestButton {

    public static void main(String[] args) {
        new TestButton();
    }

    public TestButton() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            JButton normal = createButton("Normal", Color.RED);
            JButton fixed = createButton("Fixed", Color.BLUE);
            fixed.setModel(new FixedStateButtonModel());
            setLayout(new GridLayout(1, 0));
            add(normal);
            add(fixed);
        }

        protected JButton createButton(String text, Color background) {
            JButton btn = new JButton(text);
            btn.setFocusPainted(false);
            btn.setBackground(background);
            btn.setForeground(Color.WHITE);
            return btn;
        }

    }

    public class FixedStateButtonModel extends DefaultButtonModel    {

        @Override
        public boolean isPressed() {
            return false;
        }

        @Override
        public boolean isRollover() {
            return false;
        }

        @Override
        public void setRollover(boolean b) {
            //NOOP
        }

    }

}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • +1 for the custom ButtonModel, but overriding the setPressed() method causes the ActionListener not to work. Seems like all you need is to override the getPressed() method to return false to prevent the background from changing. – camickr Mar 21 '14 at 00:17
  • @camickr Thinks, didn't test that, wasn't sure about what might happen with the change in property, guess that's one... – MadProgrammer Mar 21 '14 at 00:19
  • Nice solution. What program did you use to create that gif? – NESPowerGlove Mar 21 '14 at 02:12
  • @NESPowerGlove [LICECap](http://www.cockos.com/licecap/), free, multi platform... – MadProgrammer Mar 21 '14 at 02:14
4

You can extend JButton class and design your own appearance or just override the default bahaviour as in this exemplary code:

public class MyButton extends JButton {
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (isSelected()) {
            setBorder(BorderFactory.createEmptyBorder());
        } else {
            setBorder(BorderFactory.createLoweredBevelBorder());
        }
    }
}
Maciej Dobrowolski
  • 11,561
  • 5
  • 45
  • 67
  • 1
    @FraserPrice, Not sure I understand this solution. If you don't want the border to change then just set your own Border. You should not be overriding the paintComponent() method to do this. You question seemed to indicate you did not like the background changing color when the button was pressed. I'm not sure what a Border has to do with this. – camickr Mar 21 '14 at 00:25
  • 1
    You should never be changing the te state if the component (or ny other components) fom within any paint methods, this will set up a chain of repaint events that will consume the CPU – MadProgrammer Mar 21 '14 at 22:37
4

I always do it by calling setFocusPainted(boolean b):

btn.setFocusPainted(false);
Eng.Fouad
  • 115,165
  • 71
  • 313
  • 417
3

Painting the background when pressed is a UI implementation, so you would need to change the UI.

A simpler approach would be to create Icons of a specific color to add to your buttons. Something like:

public class ColorIcon implements Icon
{
    private Color color;
    private int width;
    private int height;

    public ColorIcon(Color color, int width, int height)
    {
        this.color = color;
        this.width = width;
        this.height = height;
    }

    public int getIconWidth()
    {
        return width;
    }

    public int getIconHeight()
    {
        return height;
    }

    public void paintIcon(Component c, Graphics g, int x, int y)
    {
        g.setColor(color);
        g.fillRect(x, y, width, height);
    }
}

Then you can display the text on top of the Icon by using:

JButton button = new JButton("1");
button.setIcon( new ColorIcon(Color.RED, 32, 32) );
button.setHorizontalTextPosition(JButton.CENTER);
button.setVerticalTextPosition(JButton.CENTER);
button.setMargin( new Insets(0, 0, 0, 0) );
camickr
  • 321,443
  • 19
  • 166
  • 288