Java 动态更改swing UIManager颜色常量,并更新现有组件

Java 动态更改swing UIManager颜色常量,并更新现有组件,java,swing,look-and-feel,Java,Swing,Look And Feel,我们有一个大的应用程序。在启动时,我们设置了一些UIManager属性,如Button.background和Panel.background。几乎所有组件都使用这些值,但有些组件具有自定义背景。 现在,我们希望用户可以选择自定义颜色,并且能够在不重新启动应用程序的情况下立即查看颜色。 为eg Button.background和Panel.background设置新值在新组件上可以正常工作,例如如果用户打开新的JDialog,但不会更新现有组件。我已经在组件上尝试了SwingUtilities

我们有一个大的应用程序。在启动时,我们设置了一些UIManager属性,如Button.background和Panel.background。几乎所有组件都使用这些值,但有些组件具有自定义背景。 现在,我们希望用户可以选择自定义颜色,并且能够在不重新启动应用程序的情况下立即查看颜色。 为eg 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
    }
}
编辑/解决方案: 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);
}
import java.awt.*;
导入java.awt.event.*;
导入javax.swing.*;
导入javax.swing.plaf.ColorUIResource;
公共类Div扩展JFrame实现ActionListener{
私人杰布顿格林;
私人朱布顿红;
私人JPanel小组;
私人JComboBox;
私有JTextField-txt;
公共静态void main(字符串[]args)引发异常{
新Div();
}
public Div()引发异常{
ColorUIResource r=新的ColorUIResource(新颜色(0255,0));
UIManager.put(“按钮背景”,r);
UIManager.put(“Panel.background”,r);
UIManager.put(“ComboBox.background”,r);
UIManager.put(“TextField.background”,r);
//UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());//工作正常,但在JButtons上不工作
UIManager.setLookAndFeel(“com.jgoodies.looks.plastic.PlasticXPLookAndFeel”);//也适用于JButton:-D
绿色=新的按钮(“应更改”);
红色=新的按钮(“不应更改”);
panel=新的JPanel();
box=新JComboBox();
txt=新的JTextField();
JPanel cp=(JPanel)getContentPane();cp.setLayout(新的GridLayout(5,1));
cp.add(绿色);
cp.add(红色);
cp.add(专家组);
cp.add(框);
cp.add(txt);
红色。挫折背景(颜色。红色);
green.addActionListener(this);
设置大小(200200);设置位置(100100);
setVisible(真);
}
@凌驾
已执行的公共无效操作(操作事件e){
Color col=((Color)UIManager.get(“Button.background”).darker();
ColorUIResource r=新的ColorUIResource(col);
UIManager.put(“按钮背景”,r);
UIManager.put(“Panel.background”,r);
UIManager.put(“ComboBox.background”,r);
UIManager.put(“TextField.background”,r);
SwingUtilities.updateComponentTreeUI(此);
}

}当摇摆能力不起作用时(它们不适用于任何情况),我就是这么做的 例如:

   JFrame frame  = new JFrame("Window");
它里面有一些组件

frame.dispose();

frame.setVisible(true);
快速 解决了update()的问题

还有一个与StackOverFlow类似的链接

我认为守则应该是:

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与其他组件不同。

如果您尝试使用绿色。例如,setBackground(Color.WHITE),它会起作用。。。当你有.setBackground()方法时,为什么要使用UIManager?它是一个巨大的应用程序,在不同的选项卡中有数千个组件等等,即使我遍历了所有组件;正如我所说,他们中的一些人有自己的背景,不应该改变。这看起来很容易解决,我真的希望这能解决问题,但事实并非如此。不幸的是,这些组件似乎还记得它们原来的颜色。好的。。您的意思是,更改所有按钮或至少一个按钮的backgroundColor()后,dispose()和SwingUtilities根本不起作用?让我再问一个问题,你使用的按钮有一些相似的东西,比如说它们都是(电视按钮(不是很好的例子,但要试着理解)?我问你这些原因是我在一个应用程序(音乐)中工作,例如,可能需要10.000首曲目,用户想要改变颜色(背景和前景)在所有的人中,一次或者一半,或者..什么likes@runholenJButton具有属性数组(3-4 GradientPaint)在UIResource中,一切都取决于您真正想要做什么,如果是关于纯Coror蛋糕,那么使用setBackground成功,否则您必须覆盖UIManagers键中的所有参数,注意应该是L&F敏感的,WIndowClasicsL&F也会忽略:-),因为Nimbus需要取消初始化(L&Fs API中类似的东西)整个L&Fmaybe操作意味着,如果在ButtonModel中缺少(似乎没有帮助)事件,我将忽略这个模糊的注释(忘记加上一个)我第一次评论说我尝试了这个,但失败了,但那只是JButton示例。我现在尝试了您的TextField.background示例,以及Panel.background、ComboBox.background等,效果很好!:-)
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);
    }
}