The Source for Java Technology Collaboration
User: Password:



Ethan Nicholas's Blog

Ethan Nicholas Ethan Nicholas is the lead engineer for the Yahoo! Publishing Tools team, and was the original author of the Swing-based Yahoo! SiteBuilder web design application. In his spare time he is developing JAXX, an XML-based user interface language for creating Java desktop applications.



Introducing Java CSS

Posted by enicholas on July 17, 2008 at 02:12 PM | Permalink | Comments (18)

How people configure Swing today

If you've ever written a non-trivial Swing program, you've probably written code that looks a lot like this:

JSlider slider = new JSlider(0, 100, currentValue);
slider.setMinorTickSpacing(5);
slider.setMajorTickSpacing(25);
slider.setPaintTicks(true);
slider.setForeground(DEFAULT_FOREGROUND);

That's an awful lot of configuration for one component, and worse: it's all compiled code, and therefore relatively inaccessible. The more experienced programmers in the audience are going to immediately (and quite rightly) complain about the setForeground() call -- that should be installed into the UIDefaults table -- and we should probably be using constants instead of those magic numbers.

But then we, in a sense, end up with an even bigger mess. Some of the slider's configuration comes from the UIDefaults table, some comes from constants defined well away from the slider itself, and some (like setPaintTicks(true)) is still buried directly in the slider's initialization code. And we still haven't fixed the real problem, that all of these values are still stored in compiled code and therefore not easy to get at or change.

Even-more-experienced coders will now suggest another change -- that we put the constants into a configuration file of some kind, rather than into code. So we perhaps write a configuration file containing something along the lines of:

default.font              = Dialog-12
default.foreground        = #000000
mySlider.minorTickSpacing = 5
mySlider.majorTickSpacing = 25
mySlider.paintTicks       = true

Problem solved! Right? Well, sort of. You've still got to write code to process this configuration file. You've got to work out how the values defined in the file actually get applied to components. slider.setMinorTickSpacing(getProperty("mySlider.minorTickSpacing")) is simple, but lame -- what happens if you add a new property to the configuration file? Unless you're specifically looking for it, it won't be respected. So you might go all the way to the logical extreme of using reflection to apply these properties by dynamically finding the relevant mutator methods.

I've seen configuration files along these lines (though the details of course differ) in many different Swing programs, and I don't think they're uncommon. I've written some myself. But there's a real problem with this approach -- you're reinventing the wheel. What you've created is in effect a very simple and limited stylesheet language. And if you're going to do that, why not just use a real stylesheet language?

Using CSS instead

There already exists a powerful, flexible stylesheet language that millions of people are familiar with. It's called CSS, and various (mostly very poor) implementations already exist for Java. With a proper CSS engine, you wouldn't need to bury the configuration in your code or burn it into proprietary configuration files. The configuration above might be expressed as:

* {
  font: Dialog-12;
  foreground: black;
}

JSlider#mySlider {
  minorTickSpacing: 5;
  majorTickSpacing: 25;
  paintTicks: true;
}

Admittedly, in this simple example there's not a clear benefit to using CSS instead of a proprietary file -- the syntax is a bit different, but the two files are about equally complex. The real benefit of CSS comes from all of the additional power it offers.

Want to only affect sliders which appear under MyColorChooser? No problem, use the selector "MyColorChooser JSlider". Or pick every label serving as a title with "JLabel.title". What about JButtons, but only when they are moused over? Use "JButton:mouseover".

What about even more complex selectors, such as "JSliders which are direct children of a MyPanel appearing in the currently active window, but only when they are set to their maximum value"? No problem, with a slight syntax extension "Window:active MyPanel > JSlider:{value == maximum}" does just the trick.

The Java CSS Engine

I mentioned above that the existing CSS implementations for Java are generally very poor. That's why I ended up creating a new one, which (hopefully) far exceeds previous CSS engines in many respects.

Click the launch button to see a simple demo of my CSS engine:

For comparison, here is the exact same application without a stylesheet:

The demo application also includes a stylesheet editor window, which allows you to update the stylesheet or turn it off altogether:

The stylesheet specifies some interesting rules, such as

JSlider#tip:{value <= 10} {
  background: red !over 0.3s;
}

The JSlider#tip portion of the selector means that this rule only applies to the JSlider named "tip". Okay, simple enough. The next part ":{value <= 10}" is what is called a programmatic pseudoclass -- basically just a boolean expression which controls whether or not the rule applies, taking the form of an EL expression evaluated using Beans Binding. So this rule applies only when the slider has a value of 10 or less.

One other unusual feature of this rule is the !over 0.3s expression. This signifies an animation, happening over a period of 0.3s. Try dragging the slider left and right to see the "good tip" and "bad tip" animations fade in and out. (Please note I'm not actually passing any judgment on tips. This is just a stupid demo. I suck at demos.)

Conclusion

Java CSS is a powerful, flexible engine for styling Swing components, supporting very powerful selectors, tons of pseudoclass states, and advanced features like animated state changes.

For full documentation or to download Java CSS, please visit the Java CSS Home Page.



August 2008
Sun Mon Tue Wed Thu Fri Sat
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            


Search this blog:
  

Categories
Community: Java Tools
Community: JavaDesktop
Community: Mac Java Community
Deployment
J2SE
JavaOne
Performance
Programming
Security
Virtual Machine
Archives

July 2008
April 2008
May 2007
March 2007
January 2007
December 2006
October 2006
September 2006
August 2006
June 2006
May 2006
April 2006
March 2006

Recent Entries

Introducing Java CSS

Java Secrets Revealed #1

Java Kernel Unmasked

Articles

Introducing JAXX: A New Way to Swing
Swing's great, except for the thousands of lines of manual layout, event wiring, data binding, etc. JAXX offers an alternative: an XML markup that offers faster and more intuitive ways to lay out and wire up your GUI, while still offering tremendous flexibility. Ethan Nicholas shows what's inside this exciting new package. Mar. 30, 2006

All articles by Ethan Nicholas »



Powered by
Movable Type 3.01D


 Feed java.net RSS Feeds