1

We have a large application. At startup we set some UIManager properties, like Button.background and Panel.background. Almost all components then uses these values, but some components have custom backgrounds. Now we would like the users to have an option of customizing their colors, and be able to view them at once, without restarting the application. Setting new values for eg Button.background and Panel.background works fine on new components, eg if the user opens a new JDialog, but will not update existing components. I have tried SwingUtilities.updateComponentTreeUI, updateUI etc on the components, but it seems that the background is allready set on the existing components and will not update. I cannot loop through all components and set background accordingly, since some backgrounds have custom backgrounds. What should I do? We use jgoodies look&feel, but it will not work in standard UIManager.getCrossPlatformLookAndFeelClassName() either. I will provide a small coding example of what I want.

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 answer seems to work on all components that I have tried except my provided JButton-example (eg Panel.background, ComboBox.background, TextField.background etc) And I even found that the L&F that we use, jgoodies, even respects this for JButton :-D So now I am happy. So code changes to the example would be:

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

}

runholen
  • 850
  • 11
  • 24
  • if you try green.setBackground(Color.WHITE) for example it works... why you want to use UIManager when you have .setBackground() method? – crAlexander Feb 04 '15 at 15:21
  • It's a huge application with thousands of components in different tabs etc. And even if I traverse all of them; as I stated, some of them have custom backgrounds and should not be changed. – runholen Feb 04 '15 at 21:06

2 Answers2

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

I believe that the code should be:

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

The UIManager will only update properties that are part of the LAF, so you need to use the ColorUIResource wrapper.

Edit:

The main idea is you need to originally set the UIManager color to use the ColorUIResource. This works for a 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);
    }
}

I'm not exactly sure why a JButton doesn't work, but as @mKorbel has mentioned, JButton is different from other components.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • @runholen JButton has arrays of properties (3-4 GradientPaint) in UIResource, everything depends of what do you really want to do, if is about the pure corored cake, then with success by using setBackground, otherwise you have to override all parameters in UIManagers key, note should be L&F sensitive and ignored by WIndowClasicsL&F as well :-), for Nimbus required to uninitialize (something similair in L&Fs API) whole L&F – mKorbel Feb 04 '15 at 21:41
  • maybe OP means, missing (it didn't seem to help) that there are events in ButtonModel, I'm would be ignore this vague comment (forgot plus one) – mKorbel Feb 04 '15 at 22:49
  • I first commented that I tried this and it failed, but that was only with the JButton-example. I have now tried your TextField.background example, and also Panel.background, ComboBox.background, etc, and it works! :-) – runholen Feb 05 '15 at 07:38
0

When SWingUtilities don't work(they dont for every situation) thats what i do For example:

   JFrame frame  = new JFrame("Window");

it has some Components inside...

frame.dispose();

frame.setVisible(true);

fast and it solve the problem of update();

Also a similar link to StackOverFlow similar problem

Community
  • 1
  • 1
crAlexander
  • 376
  • 1
  • 2
  • 12
  • This looked like an easy fix, and I was really hoping this would solve the problem, but it did not. Unfortunately the components seem to remember their original colors. – runholen Feb 04 '15 at 21:11
  • ok .. you mean that after changing the backgroundColor() of all the buttons or at least one the dispose() and SwingUtilities don't work at all? and let me ask something more the buttons you use have something similar lets say for example they are all(Tv buttons(not good example but try to understand) ? – crAlexander Feb 04 '15 at 21:31
  • i ask you these cause i work in an application(music) wich may take 10.000 tracks for example and the user want to change the color(background and foreground) of all them at once or half of them or .. what it likes – crAlexander Feb 04 '15 at 21:36