torsdag 17 februari 2011

Tweaking Nimbus

I'm just back from JFokus in Stockholm and a very good meeting with people sharing my Nb RCP interest. We might have been the only people at that Steak House that particular evening trading netbeans advice...

******** EDIT: 2011-02-19 ***************
Thanks to Geertjan's article I figured out how to make a complete redraw in real time.
Actually setting the UI to a different laf and then straight back again actually redraws the entire UI like I wanted to below.

public static void updateUI() { 
  try { 
    UIManager.setLookAndFeel(
      "javax.swing.plaf.metal.MetalLookAndFeel");
    UIManager.setLookAndFeel( 
      "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
  } catch (Exception ex) {}
  UIManager.put(nimbusBlueGrey, YOUR_NEW_COLOR);
  SwingUtilities.updateComponentTreeUI(jFrame); 
}
Strange, but it works.
************************************

At that dinner I had the opportunity to show and discus my current project's struggles with adopting the Nimbus Look&Feel to what our art director have created in photoshop.

The thing is that we want the user to be able to change his or her settings in real time so we want to change the nimbus drawing properties in real time programatically.

This can typically be done like this:

for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()){
  if ("Nimbus".equals(info.getName())) {
    UIManager.setLookAndFeel(info.getClassName());
    UIManager.put("nimbusBase", new Color(21, 21, 21));
    UIManager.put("nimbusBlueGrey", new Color(44, 44, 44));
    UIManager.put("control", new Color(40, 40, 40));
    UIManager.put("textText", Color.WHITE);
    jFrame = (JFrame) WindowManager.getDefault().getMainWindow();
    SwingUtilities.updateComponentTreeUI(jFrame);
    break;
  }
}

In my current project I run code similar like the one above in my module Installer class like this:

public void restored() {
  WindowManager.getDefault().invokeWhenUIReady(new GuiInitialiser());
}

The code above is what gets done in the GuiInitialiser.
However, and this is my main concern right now, this code behaves quite differently when I, instead of setting tha laf programatically like above, set it by adding

run.args.extra=--laf com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel

in my project's platform.properties file. The problem seem to have something to do with performing a COMPLETE and clean redrawing of the entire project UI when setting it programatically. To illustrate this I have created a small project that illustrates what I'm talking about. If you run it, you will find that the main menu "row" at the top of th screen is quite ugly.


This is because I set

  UIManager.put("nimbusBase", Color.MAGENTA);
  UIManager.put("nimbusBlueGrey", Color.CYAN);

before updating the UI the first time. However, changing the same properties after that does not redraw that part of the UI.

In this program there are some predefined settings that you can try but also a text field where you can try to change the color of any other nimbus property that you might like. However, due to the Nimbus logic of derived colors (which by the way is illustrated quite well in the application above - set nimbusBase to red and watch how red is implemented on for instance the comboBox) it is quite hard to find a color property that just instantly does what you want/expect it to.


So if your interested, you can download the project and play around with it. I hope that both the application and its source can benefit someone. Obviously this application should have been presented as a java web start, but that rendered even differently which someone also should feel very free to get back to me about...

So, if you like this, download it and experiment. Run it as is or with the laf-setting in the platform-file instead. Run it as JNLP.

Over and out!

6 kommentarer:

  1. Hi,

    I'd like to experiment with the project but the download link seems to be broken? (I got a file but it's size was zero)

    Tack så mycket =)

    SvaraRadera
  2. Ohh, sorry! The file has been replaced now, please let me know how it works out!

    /Henry

    SvaraRadera
  3. Had to hassle a bit with search-replace and JNLP codebases since the $$codebase syntax seems to be for JnlpDownloadServlet (or something that I don't have on my computer right now). Neither have NetBeans installed or any experience on that.

    After that, the project starts OK but after action or a couple of actions (like opening a menu or changing selected tab) the GUI seems to freeze. Didn't find any deadlocks with JConsole, though.

    I Don't have so much time and I neither expect you to have but if you have some idea instantly, please share =)

    best regards, Touko

    SvaraRadera
  4. Hmm, tried it out right now (in NB 7.0.1 - which is not what I used to write it...) and it worked nicely. However, rather than spending time to find whatever is not working I suggest that you look at the to classes that do all the work (GuiInitialiser.java and MainTopComponent.java) and perhaps move them into a new project that you create?

    It should work. Good luck!

    SvaraRadera
  5. That would require installing NetBeans but I could give that a try in the future when/if I have a bit spare time.

    Thanks!

    SvaraRadera
  6. Ok, yes, let me now if/how it works out in the future!
    /H

    SvaraRadera