Home > Back-end >  Setting button background with UIManager / ColorUIResource
Setting button background with UIManager / ColorUIResource

Time:11-22

Can anybody tell me, why in the following code setting a button's background fails when using a color retrieved from UIManager?
[This question is obviously too short to be accepted by Stackoverflow, but I have no more details to present.]

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

public class BackgroundColor extends JFrame {
  public BackgroundColor() {
    setSize(400,300);
    setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    setLayout(new GridLayout(0, 1, 0, 5));
    setLocationRelativeTo(null);

    JButton b= new JButton("Default");
    add(b);
    b= new JButton("" Color.RED);
    b.setBackground(Color.RED);
    add(b);
    b= new JButton("Failed: " new ColorUIResource(255, 0, 0)); // RED
    b.setBackground(new ColorUIResource(255, 0, 0));
    add(b);
    b= new JButton("Failed: " UIManager.getColor("MenuItem.background"));
    b.setBackground(UIManager.getColor("MenuItem.background"));
    add(b);
    b= new JButton("Failed: " UIManager.getColor("menu"));
    b.setBackground(UIManager.getColor("menu"));
    add(b);
    b= new JButton("" new Color(238, 238, 238));
    b.setBackground(new Color(238, 238, 238));
    add(b);
    setVisible(true);
  }
 
 
  public static void main(String arg[]) {
    EventQueue.invokeLater(BackgroundColor::new);
  }
}

CodePudding user response:

Colors of type ColorUIResource have a special meaning: they are default colors, installed by LookAndFeel. And they may be interpret by a non-standard way.

Painting of button performes the current LookAndFeel. In your case: MetalLookAndFeel, or, more precise MetalButtonUI. Painting of button is defined in method update as following:

public void update(Graphics g, JComponent c) {
    AbstractButton button = (AbstractButton)c;
    if ((c.getBackground() instanceof UIResource) &&
              button.isContentAreaFilled() && c.isEnabled()) {
        ButtonModel model = button.getModel();
        if (!MetalUtils.isToolBarButton(c)) {
            if (!model.isArmed() && !model.isPressed() &&
                    MetalUtils.drawGradient(
                    c, g, "Button.gradient", 0, 0, c.getWidth(),
                    c.getHeight(), true)) {
                paint(g, c);
                return;
            }
        }
        else if (model.isRollover() && MetalUtils.drawGradient(
                    c, g, "Button.gradient", 0, 0, c.getWidth(),
                    c.getHeight(), true)) {
            paint(g, c);
            return;
        }
    }
    super.update(g, c);
}

As you can see, if button has background of class ColorUIResource, this method provides painting of foreground only (probably due to performance reasons) by calling of method paint. And if you set a normal color as background, you avoid this behavior and call the line super.update(g, c); And here is the implementation of this method (defined in class ComponentUI):

public void update(Graphics g, JComponent c) {
    if (c.isOpaque()) {
        g.setColor(c.getBackground());
        g.fillRect(0, 0, c.getWidth(),c.getHeight());
    }
    paint(g, c);
}

Conclusion: do not use the class ColorUIResource, except you write your own LookAndFeel

  • Related