6

I have a JButton that I would like to change the background color of to white. When using the Metal Look And Feel, I achieve the desired effect with setBackground:

Metal look-and-feel-styled JButton with a white background

Unfortunately, the concept of "background color" is different when using the Windows LAF; the background color is the color drawn around the button:

Windows look-and-feel-styled JButton with a white background

I would like to use the Windows LAF, but allow the button color of this JButton to be changed to white. How do I do this?

Joseph Trebbien
  • 309
  • 1
  • 3
  • 8
  • try overriding the `paintComponent(Graphics g)` method of the `JButton`, and do your custom painting there. – mre Jun 06 '11 at 18:45
  • "I would like to use the Windows LAF" I wonder what your OSX & Linux users would like to see? I'd bet it's not the Windows LAF (even if that were practical). ;) – Andrew Thompson Jun 06 '11 at 18:51
  • @Andrew Thompson: Don't worry. I am using the system LAF, but for now the requirement is Windows only. :) – Joseph Trebbien Jun 06 '11 at 18:55
  • My first question would be "why?" What about this button requires it to be a different color and look differently from other buttons? – John Gardner Jun 06 '11 at 20:08

5 Answers5

4

I use JDK 6 on XP. It looks like the Window UI doesn't follow the normal painting rules in more ways than 1. As you noticed setBackground() doesn't work. You should be able to do custom painting by telling the component not to fill in the content area:

import java.awt.*;
import javax.swing.*;

public class ButtonBackground extends JFrame
{
    public ButtonBackground()
    {
        setLayout( new FlowLayout() );

        JButton normal = new JButton("Normal");
        add(normal);

        JButton test1 = new JButton("Test 1")
        {
            @Override
            public void paintComponent(Graphics g)
            {
                super.paintComponent(g);
                g.setColor( Color.GREEN );
                g.fillRect(0, 0, getSize().width, getSize().height);
            }
        };
        test1.setContentAreaFilled(false);
        add(test1);
    }

    public static void main(String[] args)
    {
        try
        {
//          UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
        }
        catch (Exception e2) {}

        ButtonBackground frame = new ButtonBackground();
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }
}

When you run the code as is it seems to work properly. That is when you click on the button you see the Border change. However is you run with the Windows XP LAF, the Border never changes to you don't see the button click effect.

Therefore, I guess the issue is with the WindowUI and you would need to customize the UI which is probably too complex to do so I don't have a solution.

Celuk
  • 561
  • 7
  • 17
camickr
  • 321,443
  • 19
  • 166
  • 288
  • 1
    For reference, on Mac OS X, `BackgroundButton` looks like [this](http://i.imgur.com/dRRg5.png) when `Test 1` is selected. – trashgod Jun 06 '11 at 21:04
  • @camickr @trashgod It is not about macOS, `super.paintComponent(g);` line should placed before `setColor` and `fillRect` functions, otherwise it looks like as you said which is not filled. – Celuk Apr 12 '23 at 00:05
4

You'll have to decide if it's worth the effort, but you can always create youe own ButtonUI, as shown in this example due to @mKorbel.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
2

but I still think that (modified but by Darryl) is correct UIManager.get("Button.gradient"), because would be crossplatform

EDIT: correct answer would be - Nimbus or some Custom L&F, why reinvent the wheel (by Rob)

Community
  • 1
  • 1
mKorbel
  • 109,525
  • 20
  • 134
  • 319
1

Your best option is using SwingX:

JXButton allows you to set a Painter for the background with .setBackgroundPainter(Painter) using a MattePainter achieves exactly what you want. Having that JXButton extends from JButton, the changes are minimal in your code:

Color bg = new Color(new Random().nextInt(16777215)); // Random color

JButton button = new JButton();
button.setBackground(bg);

would become

JXButton button = new JXButton();
button.setBackgroundPainter(new MattePainter(bg));
0

instead of messing with the button's background color, could you do whatever indication you're trying to show a different way?

displaying an Icon, making the button bold instead of plain text, etc.

Indicating something only through a different background color isn't always obvious, and depending on the user's system colors, may be jarring, or invisible.

for example, what if the user is running windows in "high contrast" mode?

John Gardner
  • 24,225
  • 5
  • 58
  • 76