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.
source to share
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 helpfuldarker()
.JButton b = new JButton("Test"); b.setOpaque(true); b.setBackground(Color.red.darker());
-
If you are using
Border
, remember to "put the component inJPanel
and set the border toJPanel
. -
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 }
source to share