PLAF cannot change button color

We have a program that can switch between day (high contrast) and night (low contrast) modes. This is done by changing the appearance on the fly. It works for almost all components, but some ignore background color changes. In particular, I noticed that buttons, comboboxes and table headers ignore changes in PLAF.

Here's a sample program with a button. Am I doing something wrong? Does it somehow depend on the OS? (I'm on OSX)

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.plaf.ColorUIResource;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

public class Demo extends JFrame {
   public static void main(String[] args) {
      new Demo();
   }

   public Demo() {
      setTitle("PLAF button test");
      final Demo thisWindow = this;
      final JButton button = new JButton("Click me!");
      button.addActionListener(new ActionListener() {
         @Override
         public void actionPerformed(ActionEvent e) {
            Color curColor = UIManager.getColor("Button.background");
            ColorUIResource targetColor;
            if (curColor.equals(new Color(32, 32, 32))) {
               targetColor = new ColorUIResource(192, 192, 192);
            }
            else {
               targetColor = new ColorUIResource(32, 32, 32);
            }
            System.out.println("Setting new color to " + targetColor +
               " because old color was " + curColor);
            UIManager.put("Button.background", targetColor);
            SwingUtilities.updateComponentTreeUI(thisWindow);
         }
      });
      add(button);
      setMinimumSize(new java.awt.Dimension(200, 200));
      setVisible(true);
   }
}

      

And here is the result I get when I run this program and click the button:

Setting a new color to javax.swing.plaf.ColorUIRsource [r = 32, g = 32, b = 32] because the old color was com.apple.laf.AquaImageFactory $ SystemColorProxy [r = 238, g = 238, b = 238 ]

Setting a new color to javax.swing.plaf.ColorUIResource [r = 192, g = 192, b = 192] because the old color was javax.swing.plaf.ColorUIResource [r = 32, g = 32, b = 32]

Setting a new color to javax.swing.plaf.ColorUIResource [r = 32, g = 32, b = 32] because the old color was javax.swing.plaf.ColorUIResource [r = 192, g = 192, b = 192]

Setting a new color to javax.swing.plaf.ColorUIResource [r = 192, g = 192, b = 192] because the old color was javax.swing.plaf.ColorUIResource [r = 32, g = 32, b = 32]

So, the UIManager thinks that the color changes, but the visible color on the screen does not change.

Any advice is appreciated. Thank you for your time.

+3


source to share


1 answer


Does it somehow depend on the OS?

The effect is OS dependent only in the sense that the UI delegate controls the appearance of the component, and each supported framework defines a default Look and Feel . On Mac OS X the default is com.apple.laf.AquaLookAndFeel

; here is the relevant source . As shown in the UIManager Defaults provided here, the UIManager

for key "Button.background"

has a light gray value

com.apple.laf.AquaImageFactory$SystemColorProxy[r=238,g=238,b=238]

      



but the allocated space is completely covered by the native component. A similar effect hides the light pink placeholder shown for "RadioBUtton.icon"

. Some mitigation strategies:

  • As suggested here , you can set the background of the included JPanel

    .

  • As suggested here , you can use setOpaque()

    to tint the background; Tint may be helpful darker()

    .

    JButton b = new JButton("Test");
    b.setOpaque(true);
    b.setBackground(Color.red.darker());
    
          

  • If you are using Border

    , remember to "put the component in JPanel

    and set the border to JPanel

    .

  • Using a control such as the one shown here , let the user select their preferred Look and Feel; keep the selection in the instance java.util.prefs.Preferences

    .

  • Direct the user to the contrast settings in Mac OS X Accessibility System Preferences panel.

  • Wrap your platform-specific code in a suitable predicate.

    if (System.getProperty("os.name").startsWith("Mac OS X")) {
        // Specific to Mac OS X
    }
    
          

+3


source







All Articles