How to change the background color for JPanels with Nimbus Look and Feel?
Asked Answered
S

3

5

I want to use a different background color for all my JPanels in an application. How can I do that when using Nimbus Look and Feel?

I follow Changing the Color Theme to change the color of components in Nimbus Look and Feel.

It only works sometimes, randomly. If I set a PropertyChagneListener before I change the color, it is only notified once.

Here is some test code:

public class RedPanels extends JFrame {

  public RedPanels() {
    JPanel panel = new JPanel();
    add(panel);
    setPreferredSize(new Dimension(100, 100));
    pack();
    setVisible(true);
  }

  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {

      @Override
      public void run() {

        try {
          for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                UIManager.setLookAndFeel(info.getClassName());
                UIManager.getDefaults().addPropertyChangeListener(
                                               new PropertyChangeListener() {

                  @Override
                  public void propertyChange(PropertyChangeEvent event) {
                    if (event.getPropertyName().equals("Panel.background")) {
                      System.out.println("color changed");
                    }

                });
                UIManager.put("Panel.background", new Color(255,0,0));
                break;
            }
          }
        } catch (Exception e) {
            // Nimbus is not available.
        }
        new RedPanels();
        }
    });
  }
}
Sobriety answered 23/11, 2011 at 17:34 Comment(8)
I'd put in some code to allow you to see if someone/something else clobbered Panel.background.Childers
@EdStaub: I added an PropertyChangeListener for Panel.background now, see my code. But it's never notified, not even when I set the color.Sobriety
again (my fault, unconcentrated, time for some food ;-) The only property the UIManager knows of is "lookAndFeel", that is it notifies its listeners about a change of the LAF, but not about changes of any values stored into it (afair) BTW, not sure if Nimbus honors the background color stored in the ui, there had been issuesKeesee
@kleopatra: You are right, I have updated my code with the propertyChangeListener, now it listens on UIDefaults.Sobriety
@kleopatra: Yes, this seem to be such an issue. I followed this tutorial Changing the Color ThemeSobriety
Apologies, yes, I see it now. @Keesee I do see the need to repaint when the lnf changes, but you did mention that it is false. Did I miss something?Bilek
@Vern: I set the colors before the interface is initiated. So it never changes.Sobriety
@Sobriety I like what you have above (including Igor's answer below). But how can I change, say, the color of the background panel on the fly at arbitrary points long after the UI has been created an instantiated?Alaynaalayne
E
7
UIManager.getLookAndFeelDefaults().put("Panel.background", Color.RED);
Endothelioma answered 25/11, 2011 at 7:22 Comment(0)
T
2

there are three ways

1) override nimbusBase for set DerivedColor

2) create own Painter, only one example is there -> aephyr codesource,

3) simple and dirty hack to set the Color directly

enter image description here

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

public class NimbusJPanelBackGround {

    public NimbusJPanelBackGround() {
        JPanel p = new JPanel();
        UIDefaults nimbusOverrides = new UIDefaults();
        nimbusOverrides.put("Panel.background", Color.blue);
        p.putClientProperty("Nimbus.Overrides", nimbusOverrides);
        SwingUtilities.updateComponentTreeUI(p);

        JPanel p1 = new JPanel();
        nimbusOverrides = new UIDefaults();
        nimbusOverrides.put("Panel.background", Color.green);
        p1.putClientProperty("Nimbus.Overrides", nimbusOverrides);
        SwingUtilities.updateComponentTreeUI(p1);
        p1.setBorder(new LineBorder(Color.black, 1));

        JPanel p2 = new JPanel();
        nimbusOverrides = new UIDefaults();
        nimbusOverrides.put("Panel.background", Color.ORANGE);
        p2.putClientProperty("Nimbus.Overrides", nimbusOverrides);
        SwingUtilities.updateComponentTreeUI(p2);

        JFrame f = new JFrame();
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        f.add(p, BorderLayout.NORTH);
        f.add(p1, BorderLayout.CENTER);
        f.add(p2, BorderLayout.SOUTH);
        f.setSize(200, 100);
        f.setLocation(150, 150);
        f.setVisible(true);
    }

    public static void main(String[] args) {

        try {
            for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(laf.getName())) {
                    UIManager.setLookAndFeel(laf.getClassName());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                NimbusJPanelBackGround nimbusJPanelBackGround = new NimbusJPanelBackGround();
            }
        });
    }
}
Treenatreenail answered 23/11, 2011 at 18:50 Comment(4)
No, it's not an alternative to set the colors for every component, it's hundreds of them. I need a way to change the colors for all of them in one place.Sobriety
you can put component with same properties (meaning BackGround, Foreground, Border, Font) to the whatever Array and change that this way, check aephyr sourcecode, I think that there are all three ways :-)Treenatreenail
I think the only way to go is to stop using Nimbus.Sobriety
@Sobriety as you decided, note you have to calculate that other Custom L&F are so sensitive to EDT, no suprises :-)Treenatreenail
K
2

Looks like a bug in jdk6, Panel.background one of the properties not taken. Following works in jdk7 (note the sequence: first set the color, then the LAF)

 UIManager.put("Panel.background", new Color(255,0,0));
 UIManager.setLookAndFeel(info.getClassName());

My guess is that it's still somehow buggy, as Nimbus is supposed to update its properties on receiving any change in the managers setting, so reversing the sequence to first set Nimbus, then put the color) should work as well, but doesn't even in jdk7

 UIManager.setLookAndFeel(info.getClassName());
 UIManager.put("Panel.background", new Color(255,0,0));
 //UIManager.put("control", Color.MAGENTA);

Seems to be specific to Panel.background (and most probably a bunch of others), "control" is okay in both jdks, both before and after setting the LAF.

Keesee answered 24/11, 2011 at 8:54 Comment(2)
I use JDK7 for all my tests, so the they only works "sometimes" in JDK7, even the first of your examples.Sobriety
@Sobriety hmm ... you mean: running your code with the put("Panel.background", ...) moved to the start of the try block only works sporadically? Or that other properties don't work? or ...? Anyway, that sounds bad - hoped that jdk7 had resolved most of the Nimbus quirks ...Keesee

© 2022 - 2024 — McMap. All rights reserved.