Nimbus UIManager UIDefaults

Nimbus is completely configured by properties in the UIManager defaults table. In my last blog I showed a simple example of how to skin a single component. This gave you a sneak peek into the power of these properties. Lots of people have asked for a complete list of properties that can be set, well its simple just grab UIManager.getLookAndFeelDefaults() and iterate over the contents of the map and print the keys and values and there you go. Well I am not that cruel so I did the work for you and will include a link to a complete table of them at the end. But before I get to that let me explain how they work.

Nimbus properties follow some rules and you can not only use the property keys that we have added in as default but you can create your own. Nimbus Look and Feel scans the UIDefaults table when ever you add a property with UIManager.put(<<key>>,<<value>>) then updates its internal state. When that new property matches the current state of the component it applies to then it will be applied to that component. Properties cascade like CSS and the most specific matching one is used.
Example:

  • foreground = Color.BLACK
  • Label.foreground = Color.BLUE
  • Label[Disabled].foreground = Color.GRAY
  • "SomeLabel"[Disabled].foreground = Color.WHITE

In these examples foreground applies to the foreground of all regions of all components, Label.foreground applies to only Label components, Label[Disabled].foreground applies to only Label components in the Disabled state. "SomeLabel"[Disabled].foreground applies to all components named “SomeLabel” that are in the disabled state. Hopefully that also explains the different ways you can write a rule to match a Component. The only 2 cases that are not covered here are Component.Region.foreground which lets you specify a sub-region of a component and ComponentA:ChildComponentB.foreground which lets you specify a ChildComponentB contained within ComponentA. You can see many examples of these in the complete table below and then play with writing your own. For example you can use the “name” property of a component in a similar way to “class” in CSS, say naming a bunch of buttons “hotButton” and then specifying new rules for them in the defaults table. I already explained in my last blog how you can override the global defaults on a single instance bases which matches the “style” attribute with HTML CSS.

Colors in Nimbus are derived, which means there are a core set of colors which are constants and all the other colors are calculated from those. This means you can simply change those and the 1000s of other colors that are related and used in the painters will update to reflect the new base color. These colors are shown in the “Primary Colors” section of the table. The colors in the “Secondary Colors” section are derived from those in the “Primary Colors” section but themselves are used as the base colors for other colors. You may need to change the secondary colors to tweak the results of changing the primary ones if you are not happy with the results. You can you derived colors in your own code as well so that you colors can change when the primary colors change. This will allow you to make your application color theme-able idea for white label branding etc. The method you need is on NimbusLookAndFeel called getDerivedColor :

/**
 * Get a derived color, derived colors are shared instances and is color
 * value will change when its parent UIDefault color changes.
 *
 * @param uiDefaultParentName The parent UIDefault key
 * @param hOffset             The hue offset
 * @param sOffset             The saturation offset
 * @param bOffset             The brightness offset
 * @param aOffset             The alpha offset
 * @param uiResource          True if the derived color should be
 *                            UIResource, false if it should not be
 * @return The stored derived color
 */
public Color getDerivedColor(String uiDefaultParentName,
               float hOffset, float sOffset, float bOffset, int aOffset,
               boolean uiResource)

Hopefully the rest will make sense as you read though the table and look at all the examples. After that its just a matter of try playing with some and see what you can do. I hope you see that power in this that Richard Bair and I designed and hoped would be useful. The complete defaults properties table is way to big to include in this post so I have put it on a separate page.

If you would like to see how I made this list, here is the code that creates the html.

Java Icon
NimbusBrowser.java
 

56 Responses to “Nimbus UIManager UIDefaults”

  1. Matt Nathan Says:

    Wow, that’s really useful. I like the way you have ‘intelligent’ keys for your UI defaults, very intuitive, also nice presentation of the values for the properties. It also makes it nice and easy to see where a painter may not scale particularly well (FileChooser[Enabled].upFolderIconPainter for example) or at all (Spinner:”Spinner.nextButton”[Disabled].foregroundPainter).

    What is the policy of adding additional Component.States? for example if you wanted to add a UnfocusedWindow state to say the menu bar?

    Also, I think it’s “the quick brown fox jumps over the [i]lazy[/i] dog” ;-)

  2. Tom Says:

    Exactly what I was looking for, thanks a million!

  3. Eric Burke Says:

    This is perfect for what I’m doing right now. This is already an invaluable resource, thank you so much for posting this.

  4. hLk Says:

    I get this error with java 1.6.0_10rc:
    Exception in thread “AWT-EventQueue-0″ java.lang.ClassCastException: java.lang.StringBuffer cannot be cast to java.lang.String
    at NimbusBrowser$1.run(NimbusBrowser.java:81)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

    Quick fix is tu replace line 81 with:

    String key = null;
    if (keyObj instanceof String) {
    key = (String) keyObj;
    } else if (keyObj instanceof StringBuffer) {
    key = ((StringBuffer) keyObj).toString();
    } else {
    throw new IllegalArgumentException();
    }

  5. Sgt Garcia Says:

    How do you set properties for JTextField, JPasswordField… when the “editable” property is set to false (read only).

  6. Robert Lebel Says:

    Very useful, thank you very much for this !

  7. Stig Says:

    I cannot get any styling to work. Should’nt

    UIManager.put(”Panel.background”, new Color(255,255,255));

    give me white panels? It will not work with Nimbus but works fine with Widnows or Metal.

  8. emzic Says:

    hello, i can confirm the problems posted by hLk and Stig.

    i can neither get any skinning to work nor does the provided example compile on jdk6u10rc2.

  9. Jasper Potts Says:

    Thanks guys for the info on 6u10 RC2 I will try and find out what happend, how it got broken :-(

  10. Jasper Potts Says:

    I am still tracking down the issue but I have a workaround. You just need to swap the order of the two lines:

    slider.putClientProperty(”Nimbus.Overrides”,sliderDefaults);
    slider.putClientProperty(”Nimbus.Overrides.InheritDefaults”,false);
    to
    slider.putClientProperty(”Nimbus.Overrides.InheritDefaults”,false);
    slider.putClientProperty(”Nimbus.Overrides”,sliderDefaults);

    That should fix it for now. I just can’t work out how this could have broken as there were no code changes between RC and RC2 any where near Nimbus.

  11. Iain Milne Says:

    It seems to be broken for me too, but in RC1. I must be missing something in your reply about the slider.putClientProperty() - how does that relate to wanting to perform UIManager.put(”background”, Color.whatever…) ?

  12. Mats Says:

    Even with that fix there is tons of stuff that do not seem to work. For instance, changing the selection color of a JComboBox (in the drop down list). I have tried every possible key and it does not change… And I am fairly certain I am doing things right as am doing the exact same thing as is being done in the NimbusDefaults class.

    Changing the selection color does not work even if I change the actual nimbus defaults: plaf.getDefaults().put()

  13. Mats Says:

    Turns out you have to change the “List[Selected].textBackground” to change the selection color of the JComboBox drop down list… That did not make sense to me.

  14. Andre Says:

    I run into the same problems as emzic. Updating the UIManager with some primary and secondary colors does work, but setting a panel’s background to white (as mentioned above) doesn’t change anything. Help, please!

  15. Jasper Potts Says:

    Stig, Andre, emzi: There is 2 parts to that issue first is you need [Enabled] in there otherwise the default value which has Panel[Enabled].background is considered a better match and replaces Panel.background. So if you have the line:

    UIManager.put(”Panel[Enabled].background”, Color.BLUE);

    Then that will work, almost it now comes the second issue. We are caching the values read from UIDefaults which was critical for performance and they are not being cleared at the moment. I am trying to find a solution to this bit. If you put the UIManager.put(”Panel[Enabled].background”, Color.BLUE); line before creating any Swing component then it will work. Any later then it will be cached and not read again. Hope that helps for now and I will try and find a better answer.

  16. Andre Says:

    Jasper, thanks alot for the quick reply. Much appreciated!

    I wonder .. there is no key “Panel[Enabled].background” in the “Nimbus UIDefaults Properties List” that you link to. Does this mean that whenever some key doesn’t seem to work, we should add something like [Enabled] or [Disabled] to the key? If yes, this very Properties List is a little irritating as it sometimes mentions the “states” and sometimes doesn’t.

  17. Iain Milne Says:

    Sorry to bug you again Jasper, but could you help out with the following:

    // Works
    UIManager.put(”Panel[Enabled].background”, new Color(240, 240, 240));
    // Doesn’t work
    UIManager.put(”background”, new Color(240, 240, 240));
    // Doesn’t work
    UIManager.put(”menu”, new Color(255, 255, 255));
    // Works
    UIManager.put(”nimbusOrange”, new Color(51,98,140));
    // Doesn’t work
    UIManager.put(”List.disabled”, new Color(255, 255, 255));

    In my case, I’m basically trying to make the scheme look a little less gray. Ideally, I’d like to be able to set a single background color for panels/windows/etc. The other tweaks are to get a Windows-style white menu background and to reduce the “woah” effect on the orange progress bars that most people seem to have :-)

    I’d also like to globally shrink the font size too but the following only seems to work on a couple of components:
    UIManager.put(”font”, new Font(—whatever—));

  18. Jasper Potts Says:

    Iain: The issue with some of the UIManager defaults like “background” in fact most of the short simple names without states are just place holders for backwards compatibility with BasicUI, they are not used by Nimbus painters. Also Nimbus always uses the most specific rule so always look for the longest most exact rule that matches what you are after and that will most likely be what you need.

    On the font issue try the “defaultfont” key but make sure you set it early like before setting LAF to Nimbus.

  19. Paul Blessing Says:

    Am I missing them somewhere, or are there no keys to allow setting a backgroundPainter on a ToolBar:Button other than [Focused+MouseOver], [Focused+Pressed], [Focused], [MouseOver], and [Pressed]? I’m wanting to be able to set a backgroundPainter for a toolbar button in its other states as well.

  20. Christian Says:

    Jasper, thats really good work.
    I am currently thinking of adapt Nimbus to be the base LAF for my companies applications. (currently jgoodies plasticxp)
    But I have one more specific requirement. We use our LAF implementation to let the application grow to fit touchscreen requirements. So I need to change the default preferred size behaviour for textfields, buttons etc dynamically and on the fly.
    How would that be possible using Nimbus? any uimanager properties for that?

  21. Stefan Gürtler Says:

    I have found an issue: Create a context Menu with an icon and a sub-menu. The icon and text in context menu is not aligned to the right side of the context menu panel but to the left. The arrow for opening the submenu therefore is placed over the label of the menu entry of the submenu. Judging from the space in-between the left border of the context menu panel and the start of the menu item label on one side and the space between the arrow and the right border of the context menu panel (They seem to equal), I would guess there is an alignment issues!

    Expected layout of context menu:

    |Sub menu label |> |

    Actual layout of context menu:

    | Sub menu |>el|

    ‘|>’ indicates the position of the arrow.

    This issues was observed on both windows and linux.

  22. Stefan Gürtler Says:

    Correction:
    The icon and text in context menu is not aligned to the LEFT side of the context menu panel but to the RIGHT.

  23. Jasper Potts Says:

    Stefan: Can you file a bug for that on the Sun site and we will look into fixing it in the next round of Nimbus bug fixing

  24. Tbee Says:

    I’m having some troubles with Nimbus and TableCellRenderers.

    Nimbus uses a black-on-white for regular, but a white-on-blue for selected cells. My cell renderer and editor consist of a panel where two jtextfields and two buttons are present. One textfield is editable. How do I redirect the color info to the editable textfield, so it foreground is white when it is selected?

  25. Tbee Says:

    And the automatic margin and gaps that Nimbus adds, also are a problem. Nimbus surely isn’t a drop-in replacement for existing layouts. For example: stand alone images that can be clicked upon (an ImageButton) which are renderer by using JButton with all paints turned off (border, background, etc) still have these huge margins. So I have written a custom ImageButton extending JLabel instead of JButton.

    And it even gets worse when these components are used in JTables. I have to set the row height to 30 pixels in order to show a JButton with a 16×16 icon in it (to be precise: I added a “autosize rows” feature to my JTable, so this is handled automatically). Maybe it would be wise to reduce these margins when a component is used as a cellrenderer/editor.

  26. Tbee Says:

    Oh, other example: I have a screen which does some precies layouting, including gaps and margins using MigLayout. When Nimbus shows this screen, there are all kinds of extra margins which basicaly voids the margins done in the screen.

    I understand what Nimbus tries to do with the automatically adding of whitespace to screens, but it should be optional.

  27. Jethro Borsje Says:

    Nice post, thank you for the info.

    However, I found a few problems:
    [1] - Label.foreground does not work, but Label.textForeground does the trick
    [2] - I can not seem to get the “SomeLabel”.textForeground example working. This is my code:
    [code]package swing.nimbus;

    import java.awt.Color;
    import java.awt.GridLayout;

    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.border.EmptyBorder;

    import com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel;

    public class NimbusUIDefaultsTest
    {
    public static void main(String[] args) throws UnsupportedLookAndFeelException
    {
    NimbusLookAndFeel laf = new NimbusLookAndFeel();
    laf.getDefaults().put(”\”SomeLabel\”.textForeground”, Color.BLUE);

    UIManager.setLookAndFeel(laf);

    // Create the frame and show it.
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setContentPane(buildPanel());
    frame.pack();
    frame.setResizable(false);
    frame.setVisible(true);
    }

    private static JPanel buildPanel()
    {
    JLabel lbl = new JLabel(”Enter name here:”);
    lbl.setName(”SomeLabel”);
    JTextField field = new JTextField();
    field.setColumns(10);
    JButton valid = new JButton(”Valid”);
    JButton invalid = new JButton(”Invalid”);

    JPanel retval = new JPanel(new GridLayout(2, 2));
    retval.add(lbl);
    retval.add(field);
    retval.add(valid);
    retval.add(invalid);
    retval.setBorder(new EmptyBorder(4, 4, 4, 4));

    return retval;
    }
    }[/code]

    what am I doing wrong?

  28. Olivier Gout Says:

    Thanks a lot !
    It’s very useful for the Nimbus theme tool I am working on.

  29. Mark Says:

    Nimbus is looking awesome. Just remind management that the last 10% of development takes the other 50% of effort and not to stretch it out over so many years that nobody cares anymore.
    My initial hurdle with deploying Nimbus would appear to involve the caching mechanism described in prior posts. For the next release of one of our products, we would like to have the user be able to increase or decrease the font size. The natural way to do this appears to be through the UIManager with something like this:

    public void actionPerformed(ActionEvent e) {
    try{
    UIManager.put(”Label.font”, new FontUIResource(theNewFont));
    SwingUtilities.updateComponentTree(myAppFrame);
    } catch (Throwable t) {
    t.printStackTrace();
    }

    }
    This doesn’t work in Nimbus. Is there another approach we should look at?

  30. Jasper Potts Says:

    Mark: You can set the default font for the Nimbus Look and Feel with the UIManager key “defaultFont” this will work if set before loading the look and feel. I have not tested live switching of the font and it will take some more experimenting to find a answer to that. I would have expected the Label.font to work as well not sure what is broken there. Will look into it when I get time.

  31. Kevin Says:

    There doesn’t appear to be away to set a painter on a panel or toolbar. Is this correct?

  32. Jasper Potts Says:

    Kevin: You should be able to, try “Panel[Enabled].backgroundPainter” for example. You are not limited to the options in the table I have they are just the ones that Nimbus uses, you should be able to follow the naming convention and set the paint for any component for any state including for your own custom components.

  33. GeekyCoder Says:

    Hi, Jasper.
    By default, Nimbus display the image on the right side of the tab label in JTabbedPane. How do I display the image on the left side of the label ?

  34. Adrian P Says:

    Hi Jasper,

    I’m currently trying out Nimbus for use in our project, and have come across one specific little stumbling block: I can’t seem to specify a different text foreground colour for InternalFrameTitlePanes when they’re in focus (We have colour schemes where windows being in focus and out of focus look quite different, so it is important to get this working).

    Here is the example of what I currently have (toxic colours for testing only):

    UIDefaults defaults = UIManager.getLookAndFeelDefaults();
    defaults.put(”InternalFrameTitlePane.States”, “Enabled,WindowFocused”);
    defaults.put(”InternalFrameTitlePane[Enabled].textForeground”, Color.YELLOW);
    defaults.put(”InternalFrameTitlePane[Enabled+WindowFocused].textForeground”, Color.CYAN);

    The yellow font is applied no matter if the window is in focus or not. I’ve tried all sorts of keys. All the InternalFrame-related combinations out of NimbusDefaults.java and more, but nothing seems to let me specify a foreground colour that gets applied in focus only. :/

    What am I doing wrong? Is it something obvious where I just haven’t come up with a specific correct key (in which case, can you please let me know what the key is), or is there more to this?

    Other than this internal frame foreground issue, I’ve got a few other little specific examples where I just can’t seem to come up with a correct key for a particular window/focus/selection state that we want. Really just curious if this kind of issue is key based, or if the facilities are often missing in Nimbus for very special cases and require custom painters, etc.

    Cheers,
    Adrian

  35. Jasper Potts Says:

    Adrian: This which states are supported by which components is not 100% consistent as it is based on Synth which is not 100% consistent. Most of the state handling comes from synth so you can always look at the Synth source to see what states are supported. The special”custom” states like “WindowFocused” are part of Nimbus and are managed though UIManager Keys. Look for the “States” property of the component in UIManager defaults for example: “InternalFrame:InternalFrameTitlePane.States” says “Enabled,WindowFocused” which means they are the only two states available for the component. You can add more states into that list either standard ones or custom ones if you need to. So states is one part to understand, the other is composite components. Components like InternalFrame are made from many sub-components like the title pane or the close button. Each of those sub-components needs to be addressed specifically which is where things get more complex. If we are not styling the part of a component you need in Nimbus so you have no reference for the key needed then the only way to find out what the component structure is and therefore the key to style that part is to look at the BasicLAF and SynthLAF classes for that component and see how it builds the structure. This is what we did when creating Nimbus and it often took a couple tries to get the right key :-)
    One more tip is components are not always 100% of the time in Enabled or Disabled states so you might be better of with less specific state keys like [WindowFocused] rather than [Enabled+WindowFocused]. So after all the generic tips this is what I think you need though I have not tried it.

    InternalFrame:InternalFrameTitlePane[WindowFocused].textForeground

  36. Adrian P Says:

    Hi Jasper,

    Thanks for prompt response.

    I did actually try stepping into the code when working on this, and I basically came up with a lot of the conclusions that you just confirmed for me. Good to know in black and white anyways. Before this I thought I must be doing something horribly wrong. Up until now I never really looked at Synth much either, so I thought the inconsistencies I was seeing were all in my head and/or that I was missing something major.

    “InternalFrame:InternalFrameTitlePane[WindowFocused].textForeground” actually doesn’t seem to work BTW. In fact, that format doesn’t work when specifying for [Enabled] either. But the format I use in my email above does.

    The one thing I haven’t done in detail yet is look into the BasicLAF and SynthLAF classes. I have a feeling that this is where the things I thought were missing are hiding, so I’ll look into it with that assumption from now. I think I spent too much time trying to work out how “Nimbus does stuff” in cases where it doesn’t actually do it directly. ;)

    Thanks again for responding.

    Cheers,
    Adrian

  37. Kevin Says:

    I’m having problem being able to set an attribute for named components. If I remove the quotes and change MySlider to Slider, it works fine.

    defaults.put(”\”MySlider\”.thumbHeight”, 30);

    JSlider normalSlider = new JSlider(0, 100, 50);
    normalSlider.setName(”MySlider”);

  38. Martin M. Says:

    Hello Jasper.

    I’m currently looking at Nimbus, for it might be quite useful for several projects in our company. So far it seems to be a very promising approach. Especially the ability to resize the vector-based components is interesting! But I have some problems/questions:
    - Since Nimbus is based partly on Synth, I assumed that it’s possible to externalize configured uidefaults in something like a xml file, quite similar how it is done in Synth (via “synthlaf.load(SynthDialog.class.getResourceAsStream(”style.xml”), …”). But now I have read, that this won’t be possible. Is there, or will there be a built-in way to read externalized uidefaults to initialize the nimbus laf?
    - As you wrote in your post (September 29th, 2008 at 6:51 pm on this page), you are caching all uidefaults. I understand, that this is crucial due to performance issues. Anyway, will there be a possibility to change specific uidefault values globally during runtime? I know that I can set variant uidefault values on fresh initialized components by setting the ”Nimbus.Overrides” clientproperty, but i wan’t to change them globally. This is needed for being able to write an Ui-Configuration Tool, which enables me to see changes to my gui on the fly.
    - Are there some news about the availability of the nimbus component designer you mentioned somewhere?

    Thx,
    Martin

  39. Jasper Potts Says:

    Martin:

    -There is no standard way of loading UIDefaults from file you should be very easy to do in couple lines of code and a java properties file. In Nimbus its self we have a XML file in src which get converted into Java code at compile time as that will be the fastest at runtime.
    - I have not don’t much testing of runtime changing of properties but you should be able to use SwingUtilities.updateComponentTreeUI(...) on a root component like the frame to cause all caches to be cleared and properties to be reread.
    - No news on Nimbus Designer, I would like to get it out there but I have not had time to chase management on opensourcing it or to work on it to get it to a state where it would be useful to people, sorry

  40. Martin M. Says:

    Hello Jasper.

    Thx for your quick reply! However, I’m still having a hard time changing uidefault settings globally during runtime, and currently I’m thinking, that it’s just not possible; also by using the SwingUtilities.updateComponentTreeUI() command that you mentioned. Even before your answer, I was playing around with that command, but to no avail. However, i wrote a small test class and allow myself to post it here, since I think that there may be some general interest. I shortened it as much as possible, but it should run if you just add some imports. This is on the latest jdk update (1.6u11):

    public class NimbusTestFrame extends JFrame implements ActionListener {
    private static NimbusTestFrame frame;
    private JPanel content, buttonPanel;
    private JButton button1 = new JButton(”Button1″), button2 = new JButton(”Button2″);

    public NimbusTestFrame() {
    super();

    setBounds(100, 100, 800, 111); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    init();
    }

    public static void main(String args[]) {
    try {
    // UIManager.put(”Button[Enabled].background”, Color.red); // ##01## this works globally, if commented in
    try {
    UIManager.setLookAndFeel(new NimbusLookAndFeel());
    } catch (Exception e) {}
    frame = new NimbusTestFrame();

    frame.setVisible(true);
    } catch (Exception e) {}
    }

    public void actionPerformed(ActionEvent e) {
    if(e.getSource() == button1) { // ##02##
    System.out.println(”pressed button1″);
    UIManager.put(”Button[Enabled].background”, Color.red); // this does
    UIManager.put(”Button[Enabled].backgroundPainter”, new CustomPainter()); // not work
    SwingUtilities.updateComponentTreeUI(frame);
    } else if(e.getSource() == button2) { // ##03##
    System.out.println(”pressed button2″);
    UIDefaults ud = new UIDefaults();
    ud.put(”Button[Enabled].background”, Color.blue); // change background color of button 1
    ud.put(”Button[Enabled].backgroundPainter”, new CustomPainter()); // change painter of button 1
    button1.putClientProperty(”Nimbus.Overrides”, ud);
    button1.putClientProperty(”Nimbus.Overrides.InheritDefaults”, false);
    }
    }

    private void init() {
    content = new JPanel(new BorderLayout());
    buttonPanel = new JPanel(new BorderLayout());
    button1.addActionListener(this); button2.addActionListener(this);
    buttonPanel.add(button1, BorderLayout.NORTH);
    buttonPanel.add(button2, BorderLayout.SOUTH);

    content.add(buttonPanel, BorderLayout.CENTER);
    getContentPane().add(content);
    }

    private class CustomPainter implements Painter {
    public void paint(Graphics2D g, JButton object, int w, int h) {
    g.setStroke(new BasicStroke(2f));
    g.setColor(Color.red);
    g.fillOval(1, 1, w-3, h-3);
    g.setColor(Color.white);
    g.drawOval(1, 1, w-3, h-3);
    }
    }
    }

    So, this is what bugs me:
    - Button1 sets some uidefault values and invokes SwingUtilities.updateComponentTreeUI() on the main frame. This never works! I was expecting, to see an immediate change upon pressing the button.
    - Button2 creates a new UIDefaults object and uses this “Nimbus.Overrides” client property to set new uidefaults on button1. This works.
    I hope I didn’t get something completely wrong, but as I said, the behaviour of Button1 does not seem to be correct.

    Thx again,
    Martin

  41. Martin M. Says:

    Hi again.

    Well it’s been 6 days without answer so far. Shall I take this as a ‘no. It’s currently not possible to change uidefaults globally with nimbus during runtime!’, or is there still hope that I have missed something?
    To be honest, I think this is a very crucial feature and other people have mentioned such problems already (@see entry from Mark on ‘December 10th, 2008 at 7:30 pm’).
    So I think this issue deserves some extra time for looking into it.

    Cheers,
    Martin

  42. Kevin Says:

    I have noticed some strange behavior with popup menus and menuitem settings.

    The “MenuItem[MouseOver].textForeground” will work unless you also specify “MenuItem[Enabled].textForeground”. I have tried using Enabled+MouseOver instead of just MouseOver, but that didn’t work. It ends up using the Enabled color instead of the MouseOver color.

    For PopupMenu, the “PopupMenu[Enabled].backgroundPainter” doesn’t appear to use the “PopupMenu.background” color. The RBG values produce by the painter is completely different than the value set for backgroundPainter.

    Also, is there any way to create a painter for text on all controls? I would like to be able to create shadow or chisel effects for text. From my testing, I could create a background painter, draw the text here, and then dispose the graphics() before it is done. This works, but it makes the developer calculate the position of the text. A text painter would give you the rectangle for the text.

    Thanks!

  43. Luca Morettoni Says:

    I need to change JButton’s color on some frame, but I see a strange problem with some kind of color. To change the color I use this simple code:

    jButton1.setBackground(col);

    when I try to use a RED color with:

    col = Color.RED; // or new Color(255, 0, 0);

    I have a “flat” button, but with:

    col = new Color(151, 174, 20);

    I see the light effect on the button…

    any hint?

  44. Nikola Says:

    Is there a way to change
    ProgressBar[Enabled+Indeterminate].foregroundPainter and ProgressBar[Disabled+Indeterminate].foregroundPainter

    I’ve tried this but without any success:
    UIDefaults ud = UIManager.getLookAndFeelDefaults();
    jProgressBar1.putClientProperty(”Nimbus.Overrides.InheritDefaults”, false);
    jProgressBar1.putClientProperty(”Nimbus.Overrides”, ud);
    ud.put(”ProgressBar[Enabled+Indeterminate].foregroundPainter”, ud.get(”ProgressBar[Enabled].foregroundPainter”));
    ud.put(”ProgressBar[Disabled+Indeterminate].foregroundPainter”, ud.get(”ProgressBar[Disabled].foregroundPainter”));
    SwingUtilities.updateComponentTreeUI(this);

    Thanks!

  45. Jasper Potts Says:

    Nikola: I can’t remeber the correct order but there is a big in where the ordering of the:
    jProgressBar1.putClientProperty(”Nimbus.Overrides.InheritDefaults”, false);
    jProgressBar1.putClientProperty(”Nimbus.Overrides”, ud);
    lines matters and i would also test if doing the ud.put lines frmore the “jProgressBar1.putClientProperty(”Nimbus.Overrides”, ud);” line makes a change.

    Even if you do that I am not quite sure what you will see visually as there is special code to animate the indeterminate progress bars. What visual effect are you trying to get?

  46. Nikola Says:

    I would like to change Nimbus indeterminate progressbar look. It looks kind a silly to me.
    Here is the same progressbar in netbeans (running Nimbus):
    http://img291.imageshack.us/img291/5296/14479359.jpg

  47. Paul Says:

    I’ve recently changed to using Nimbus as my default Look and Feel - I definitely think it should be the default look and feel for Java 7. Its brilliant :-)

    Like Nikola, I would like to be able to change the default indeterminate progress bar look to the tiled effect as seen in Netbeans 6.5 when you change the look and feel to Nimbus as in Nikola’s picture. I’ve seen it happen in a colleagues application but he has only set indeterminate to be true. Is there another way to do this?

  48. Sandro Says:

    Hallo Jasper

    We tried to change the “background” color - but it doesn’t work. We want to change Nimbus so it looks lees gray, but we won’t change every color manually.

    What can we do? We use Java 6_12

    Many thanks - and by the way, nimbus is just great - hopefully our requirement is possible.

  49. Sandro Says:

    I’ve found the solution:

    UIManager.put(”nimbusBase”, new Color(0xE2C0A9));
    UIManager.put(”nimbusBlueGrey”, new Color(0xE2C0A9));
    UIManager.put(”control”, new Color(0xE2C0A9));

    for(LookAndFeelInfo laf: UIManager.getInstalledLookAndFeels()) {
    if (laf.getName().equalsIgnoreCase(”nimbus”)) {
    UIManager.setLookAndFeel(laf.getClassName());
    break;
    }
    }

    Found on the PDF: http://developers.sun.com/learning/javaoneonline/2008/pdf/TS-6096.pdf?

    Thanks people – really, really great work!

  50. Jasper Potts Says:

    Nikola & Paul: I assume Netbeans guys have written their own progressbar UI or painter reusing the standard progressbar painter from Nimbus. The code for Nimbus will be going into OpenJDK very soon then you will be able to see the source code for the current implementation, it should not be hard to change.

  51. Paul Says:

    Jasper: I’ve seen this animation on other applications where the standard progress bar is used. It changes between the standard animation and the animation as seen in the netbeans screenshot. I’ve seen the source code for my colleagues application and there is no code to change the painter or the UI.

  52. Jasper Potts Says:

    Paul: Its defiantly not something coded into standard Nimbus it could be the result of some odd bug causing it. I have never seen it before though. I think the standard Synth way of painting might be that so something might be causing the Synth algorithm to take over from the Nimbus one for indeterminate progress bars but I have no idea of the top of my head what might be causing it.

  53. Paul Blessing Says:

    From my observations, the Nimbus indeterminate progress bar seems to flip between the two different animations depending on whether the progress value is at 100% or not. I’d vote for the tiled-looking one to be the default as well - the normal one is indeed rather strange looking.

  54. Jasper Potts Says:

    Paul: Ok that might make sense, how random. The default look is what was designed by the designer for the Nimbus, Nimbus is not only a Java LAF it is also a GTK theme on Solaris and a Web theme for other Sun products. So the Java version needs to match the others so I could not freely change the look of things.

  55. Alexander Smith Says:

    Hi Jasper. Nimbus is incredibly flexible. Thanks for your work. I did want to add my voice to those who have already asked how to get named components to accept styles added to the UIDefaults. Your example above with a component named “SomeLabel” doesn’t seem to work. Is this feature unavailable in the current version of Nimbus?

  56. Endre Stolsvik Says:

    Compared to the BasicLookAndFeel, which I thought you’d inherit through Synth, you change the parameter names for already established parameters, as well as how parameters are read.

    I refer to e.g. the BasicTabbedPaneUI.installDefaults(), where a bunch of parameters are read, e.g. “TabbedPane.tabAreaInsets”.

    This parameter you have seemingly changed to “TabbedPane:TabbedPaneTabArea.contentMargins”.

    Although I get the rationale - to get a consistent and meaningful hierarchy of names - this does however make for a break in the ability to LaF-independently change aspects of the currently installed LaF.

    For most other existing LaFs, one can for example change this particular inset by using that particular Basic-defined UIDefaults parameter, and thereby make room for “leading” and “trailing” components before and behind the tabs (the “stick-uppers”) themselves (e.g. a “close” button, or a “new tab” button, or for my case, the minimize, maximize and close frame buttons).
    This at least works for Windows (both Sun and JGoodies extended), Motif, Metal and the third party Substance.
    However, when setting the LaF to NimbusLookAndFeel, this particular property doesn’t work anymore, and must be replaced with the above mentioned Nimbus specifics.

    Furthermore 1: Contrary to the article, I find that Nimbus only reacts to settings on the form UIManager.getLookAndFeelDefaults().put(..), not UIManger.put(..) (as the article states), nor UIManager.getDefaults().put(..). This is contrary to the other themes, where the “user-modifiable” defaults-table (IIUC) getDefaults() are indeed reacted to.

    Furthermore 2: Contrary to all the other themes, it does not seem possible to change a value after the affected value is first read: After e.g. a JTabbedPane is instantiated, it is no longer possible to change that LaFDefaults value - such changes are ignored. This means that the following particular hack cannot be employed for Nimbus: set one UIDefaults value, then instantiate “the special” component. Then set the default/standard UIDefaults value, and instantiate the rest. Since all the other themes read properties upon instantiation (in the installDefaults() method), the special component will end up with the special value compared to the others. On Nimbus, all components gets the last value that is set before the first component is created. (Granted, on LaF (re)sets, this fails, and the special will also get the latter value. But it /is still possible/ to overcome that problem too using more hacks (!): Install a pro-listeners that enables a sort of “around advice” on the installDefaults method, and you can keep the hack up)

    GRANTED, you mention that you have a very nice fix for this overall issue, which should have been in ALL themes: the name-based “CSS”-style cascading styling (as well as the component-specific client properties UIDefaults-setting). This indeed seems lovely. However, since the older/other themes doesn’t have this, while Nimbus doesn’t cover the old way of doing things - one does end up in an awkward situation.

    I therefore suggest a three-fold modification to Nimbus: That you fix the “Furthermore 1″ (Nimbus should properly react to properties set by the user, as in UIManger[.getDefaults()].put(…), not only on the LaF UIManager.getLookAndFeelDefaults().put(…)).
    Change the way it re-reads all properties, that is, the “Furthermore 2″ (read the value upon instantiation - if you want to change stuff “mid flight”, you’ll have to re-set the LaF to have the new values honored).
    Finally, which really was the initial intention behind this email, I suggest that you also check the proprietary, “de-facto standards” BasicLookAndFeel UIDefaults properties, in addition to your new stuff. The new stuff overrides - but if there is nothing there, check back to the old parameters.

    I guess this seriously is a long-shot, but I just wanted to chip in these observations. I’ve found the LaF field to be VERY confusing, and sadly I feel that Nimbus actually added somewhat to this.

    However, it also leads the way for a much better future, regarding the cascading and “component named” styles.

Leave a Reply