即时更改 swing UIManager 颜色常量,并更新现有组件

Change swing UIManager color-constants on the fly, and update existing components

我们有一个大型应用程序。在启动时我们设置了一些 UIManager 属性,比如 Button.background 和 Panel.background。几乎所有组件都使用这些值,但某些组件具有自定义背景。 现在我们希望用户可以选择自定义他们的颜色,并且能够立即查看它们,而无需重新启动应用程序。 为 Button.background 和 Panel.background 等设置新值在新组件上工作正常,例如,如果用户打开一个新的 JDialog,但不会更新现有组件。我已经在组件上尝试了 SwingUtilities.updateComponentTreeUI、updateUI 等,但是背景似乎已经在现有组件上设置好了,不会更新。我无法遍历所有组件并相应地设置背景,因为某些背景具有自定义背景。我应该怎么办?我们使用 jgoodies look&feel,但它在标准 UIManager.getCrossPlatformLookAndFeelClassName() 中也不起作用。我将提供一个我想要的小编码示例。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Div extends JFrame implements ActionListener{
    private JButton green;
    private JButton red;

    public static void main(String[] args) throws Exception{
        new Div();
    }

    public Div() throws Exception{
        UIManager.put("Button.background", Color.green);
        UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
        green = new JButton("Should be changed");
        red = new JButton("Should not be changed");
        JPanel cp = (JPanel)getContentPane(); cp.setLayout(new GridLayout(2,1));
        cp.add(green);
        cp.add(red);
        red.setBackground(Color.red);
        green.addActionListener(this);
        setSize(200,100); setLocation(100,50);
        setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        UIManager.put("Button.background", ((Color)UIManager.get("Button.background")).darker());
        green.updateUI(); //Should update the green button with a new color, but doesn't
    }
}

EDIT/SOLUTION: camickrs 的回答似乎适用于我尝试过的所有组件,除了我提供的 JButton 示例(例如 Panel.background、ComboBox.background、TextField.background 等)而且我什至发现我们使用的 L&F, jgoodies,甚至尊重 JButton :-D 所以现在我很高兴。 因此对示例的代码更改为:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.ColorUIResource;

public class Div extends JFrame implements ActionListener{
    private JButton green;
    private JButton red;
    private JPanel panel;
    private JComboBox<?> box;
    private JTextField txt;

    public static void main(String[] args) throws Exception{
        new Div();
    }

    public Div() throws Exception{
        ColorUIResource r = new ColorUIResource(new Color(0,255,0));
        UIManager.put("Button.background", r);
        UIManager.put("Panel.background", r);
        UIManager.put("ComboBox.background", r);
        UIManager.put("TextField.background", r);
        //UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); //Works, but not on JButtons
        UIManager.setLookAndFeel("com.jgoodies.looks.plastic.PlasticXPLookAndFeel"); //Also works with JButton :-D
        green = new JButton("Should be changed");
        red = new JButton("Should not be changed");
        panel = new JPanel();
        box = new JComboBox();
        txt = new JTextField();
        JPanel cp = (JPanel)getContentPane(); cp.setLayout(new GridLayout(5,1));
        cp.add(green);
        cp.add(red);
        cp.add(panel);
        cp.add(box);
        cp.add(txt);
        red.setBackground(Color.red);
    green.addActionListener(this);
    setSize(200,200); setLocation(100,100);
    setVisible(true);
}

@Override
public void actionPerformed(ActionEvent e) {
    Color col = ((Color)UIManager.get("Button.background")).darker();
    ColorUIResource r = new ColorUIResource(col);
    UIManager.put("Button.background", r);
    UIManager.put("Panel.background", r);
    UIManager.put("ComboBox.background", r);
    UIManager.put("TextField.background", r);
    SwingUtilities.updateComponentTreeUI(this);
}

}

SWingUtilities 不工作时(它们不适合所有情况)这就是我所做的 例如:

   JFrame frame  = new JFrame("Window");

它里面有一些组件...

frame.dispose();

frame.setVisible(true);

快 它解决了 update();

的问题

也类似于 link 到 Whosebug similar problem

UIManager.put("Button.background", ((Color)UIManager.get("Button.background")).darker());

我认为代码应该是:

Color background = UIManager.getColor("Button.background").darker();
UIManager.put("Button.background", new ColorUIResource(background));
SwingUtilities.updateComponentTree(...);

UIManager 只会更新属于 LAF 的属性,因此您需要使用 ColorUIResource 包装器。

编辑:

主要思想是您需要最初设置 UIManager 颜色才能使用 ColorUIResource。这适用于 JTextField:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.*;

public class Div extends JFrame implements ActionListener{
    private JTextField green;
    private JTextField red;

    public static void main(String[] args) throws Exception{
        new Div();
    }

    public Div() throws Exception{
        UIManager.put("TextField.background", new ColorUIResource(Color.green));
        UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
        green = new JTextField("Should be changed");
        red = new JTextField("Should not be changed");
        JPanel cp = (JPanel)getContentPane(); cp.setLayout(new GridLayout(2,1));
        cp.add(green);
        cp.add(red);
        red.setBackground(Color.red);
        green.addActionListener(this);
        setSize(200,100); setLocation(100,50);
        setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Color background = Color.YELLOW;
        UIManager.put("TextField.background", new ColorUIResource(background));
        SwingUtilities.updateComponentTreeUI(this);
    }
}

我不太确定为什么 JButton 不起作用,但正如@mKorbel 所提到的,JButton 与其他组件不同。