Как изменить цвет фона для JPanels с Nimbus Look and Feel?

Я хочу использовать другой цвет фона для всех моих панелей JPanel в приложении. Как я могу это сделать при использовании Nimbus Look and Feel?

Я следую Изменение цветовой темы, чтобы изменить цвет компонентов в Нимб Взгляни и почувствуй.

Это работает только иногда, случайно. Если я устанавливаю 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();
        }
    });
  }
}

person Jonas    schedule 23.11.2011    source источник
comment
Я бы добавил некоторый код, чтобы вы могли увидеть, не затер ли кто-то/что-то еще Panel.background.   -  person Ed Staub    schedule 23.11.2011
comment
@EdStaub: я добавил PropertyChangeListener вместо Panel.background сейчас, смотрите мой код. Но он никогда не уведомляется, даже когда я устанавливаю цвет.   -  person Jonas    schedule 23.11.2011
comment
опять (моя вина, рассеянность, пора поесть ;-) Единственное свойство, о котором знает UIManager, это lookAndFeel, то есть он уведомляет своих слушателей об изменении LAF, но не об изменении каких-либо значений, хранящихся в нем (честно) Кстати, не уверен, что Nimbus учитывает цвет фона, сохраненный в пользовательском интерфейсе, были проблемы   -  person kleopatra    schedule 23.11.2011
comment
@kleopatra: Вы правы, я обновил свой код с помощью свойстваChangeListener, теперь он прослушивает UIDefaults.   -  person Jonas    schedule 23.11.2011
comment
@kleopatra: Да, похоже, это такая проблема. Я следовал этому руководству по Изменение цветовой темы   -  person Jonas    schedule 23.11.2011
comment
Извините, да, я вижу это сейчас. @kleopatra Я вижу необходимость перерисовки при изменении lnf, но вы упомянули, что это неверно. Я что-то пропустил?   -  person Vern    schedule 23.11.2011
comment
@Vern: я устанавливаю цвета до запуска интерфейса. Так что это никогда не меняется.   -  person Jonas    schedule 23.11.2011
comment
@Jonas Мне нравится то, что у вас есть выше (включая ответ Игоря ниже). Но как я могу изменить, скажем, цвет фоновой панели на лету в произвольных точках спустя долгое время после создания экземпляра пользовательского интерфейса?   -  person theJollySin    schedule 29.01.2013


Ответы (2)


есть три способа

1) переопределить nimbusBase для набора DerivedColor

2) создать собственный Painter, там только один пример -> aephyr codesource ,

3) простой и грязный хак для прямой установки цвета

введите здесь описание изображения

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();
            }
        });
    }
}
person mKorbel    schedule 23.11.2011
comment
Нет, это не альтернатива установке цветов для каждого компонента, их сотни. Мне нужен способ изменить цвета для всех из них в одном месте. - person Jonas; 23.11.2011
comment
вы можете поместить компонент с одинаковыми свойствами (имеется в виду BackGround, Foreground, Border, Font) в любой массив и изменить его таким образом, проверьте исходный код aephyr, я думаю, что есть все три способа :-) - person mKorbel; 23.11.2011
comment
Я думаю, что единственный выход — перестать использовать Nimbus. - person Jonas; 23.11.2011
comment
@ Джонас, как вы решили, обратите внимание, что вам нужно рассчитать, что другие пользовательские L&F настолько чувствительны к EDT, никаких сюрпризов :-) - person mKorbel; 24.11.2011

Похоже на ошибку в jdk6, Panel.background не принимает одно из свойств. Далее работает в jdk7 (обратите внимание на последовательность: сначала ставим цвет, потом ЛАФ)

 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 (и, скорее всего, для множества других), «управление» в порядке в обоих jdks, как до, так и после установки LAF.

person kleopatra    schedule 24.11.2011
comment
Я использую JDK7 для всех своих тестов, поэтому они иногда работают только в JDK7, даже в первом из ваших примеров. - person Jonas; 24.11.2011
comment
@Jonas Джонас хм ... вы имеете в виду: запуск вашего кода с помощью put(Panel.background, ...), перемещенного в начало блока try, работает только время от времени? Или что другие свойства не работают? или ...? В любом случае, это звучит плохо - надеялся, что jdk7 разрешил большинство причуд Nimbus... - person kleopatra; 24.11.2011