如何在Nimbus外观中更改JPanels的背景颜色?

5
我希望在应用程序中为所有的JPanels使用不同的背景颜色。当使用Nimbus外观时,我该如何实现?
我遵循更改颜色主题来更改Nimbus外观中组件的颜色。
这只有时候会随机起作用。如果在更改颜色之前设置了PropertyChagneListener,它只会一次被通知。
这里是一些测试代码:
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();
        }
    });
  }
}

我会加入一些代码,让你能够查看是否有其他人/物体破坏了Panel.background。 - Ed Staub
@EdStaub:我现在为Panel.background添加了一个PropertyChangeListener,请看我的代码。但是它从未被通知,即使我设置了颜色。 - Jonas
再试一次(我的错,没集中注意力,是时候吃点东西了;-) UIManager唯一知道的属性是“lookAndFeel”,它通知其侦听器有关LAF更改的信息,但不会通知任何存储在其中的值的更改(如果我没记错的话)。顺便说一句,不确定Nimbus是否尊重存储在UI中的背景颜色,因为曾经出现过问题。 - kleopatra
@kleopatra:你说得没错,我已经更新了我的代码,并加入了propertyChangeListener,现在它可以监听UIDefaults。 - Jonas
@Jonas 我喜欢你上面的内容(包括Igor下面的答案)。但是,在UI已经创建和实例化后的任意时间点,我怎么才能动态地更改背景面板的颜色? - john_science
显示剩余3条评论
3个回答

7
UIManager.getLookAndFeelDefaults().put("Panel.background", Color.RED);

2
有三种方法:
1)重写 nimbusBase 来设置 DerivedColor 2)创建自己的 Painter,这里只有一个例子 -> aephyr codesource 3)简单而不太规范的方法是直接设置颜色

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();
            }
        });
    }
}

不,这不是为每个组件设置颜色的替代方法,而是数百个组件。我需要一种可以在一个地方更改所有组件颜色的方法。 - Jonas
你可以将具有相同属性(如背景,前景,边框和字体)的组件放入任何数组中,并通过更改该数组来修改它们。查看aephyr源代码,我认为有三种方法 :-) - mKorbel
我认为唯一的出路是停止使用Nimbus。 - Jonas
@Jonas,正如你所决定的那样,请注意你必须计算其他自定义L&F对EDT非常敏感,不要有任何意外 :-) - mKorbel

2

看起来是jdk6中的一个bug,Panel.background这个属性没有被使用。在jdk7中以下代码可行(注意顺序:先设置颜色,然后再设置LAF)

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

我的猜测是它仍然存在一些错误,因为Nimbus应该在接收到管理器设置的任何更改时更新其属性,所以将顺序反转为先设置Nimbus,然后再设置颜色也应该有效,但即使在jdk7中也不起作用。

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

看起来这个问题只出现在Panel.background(以及可能还有其他一些控件)上,“control”在两个jdk中都没有问题,在设置LAF之前和之后都是如此。


我在所有的测试中都使用JDK7,所以它们只有在JDK7中“有时”才能正常工作,即使是你的第一个示例。 - Jonas
@Jonas 嗯...你的意思是:只将put("Panel.background", ...)移动到try块的开头运行代码仅偶尔起作用?还是其他属性也不起作用?无论如何,这听起来很糟糕 - 希望jdk7已经解决了大部分Nimbus的问题... - kleopatra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接