The Source for Java Technology Collaboration
User: Password:



Ethan Nicholas

Ethan Nicholas's Blog

Style Swing components using CSS

Posted by enicholas on March 24, 2006 at 08:17 AM | Comments (10)

Swing does a great job of separating data (the models) and controls (the components themselves), but it really doesn't do a good job of separating controls from presentation (the visual appearance of the controls).

Pluggable looks-and-feels help to a degree, but they are complicated to write and maintain, and on top of that they affect the appearance of every component of a particular type. There are lots of good reasons for having components of the same type have different styles attached to them, and the present-day solutions to doing this in Swing aren't fantastic.

CSS is a natural fit here. It was designed to solve exactly this problem, and on top of that it's a familiar technology which many Java programmers are already comfortable with. When writing the open-source JAXX framework, I chose to use CSS as its style language, and I think it brings unprecedented power and control to Java. Let's take a look at a simple example, the (slightly modified) Calculator from jaxxframework.org:

<Application title='Calculator'>
  <script source='Calculator.script'/>
  
  <Table fill='both' id='table'>
    <row>
      <cell columns='4'><JLabel id='display' text='0'/></cell>
    </row>
    
    <row>
      <cell columns='2'><JButton id='c' label='C' onActionPerformed='clear()' styleClass='clear'/></cell>      
      <cell><JButton id='ce'     label='CE' onActionPerformed='clearEntry()' styleClass='clear'/></cell>
      <cell><JButton id='equals' label='=' onActionPerformed='equal()' styleClass='operator'/></cell>
    </row>
    
    <row>
      <cell><JButton id='d7'   label='7' onActionPerformed='digit(7)' styleClass='digit'/></cell>
      <cell><JButton id='d8'   label='8' onActionPerformed='digit(8)' styleClass='digit'/></cell>
      <cell><JButton id='d9'   label='9' onActionPerformed='digit(9)' styleClass='digit'/></cell>
      <cell><JButton id='plus' label='+' onActionPerformed='add()' styleClass='operator'/></cell>
    </row>

    <row> 
      <cell><JButton id='d4'       label='4' onActionPerformed='digit(4)'   styleClass='digit'/></cell>
      <cell><JButton id='d5'       label='5' onActionPerformed='digit(5)'   styleClass='digit'/></cell>
      <cell><JButton id='d6'       label='6' onActionPerformed='digit(6)'   styleClass='digit'/></cell>
      <cell><JButton id='subtract' label='-' onActionPerformed='subtract()' styleClass='operator'/></cell>
    </row>

    <row>
      <cell><JButton id='d1'       label='1' onActionPerformed='digit(1)' styleClass='digit'/></cell>
      <cell><JButton id='d2'       label='2' onActionPerformed='digit(2)' styleClass='digit'/></cell>
      <cell><JButton id='d3'       label='3' onActionPerformed='digit(3)' styleClass='digit'/></cell>
      <cell><JButton id='multiply' label='x' onActionPerformed='multiply()' styleClass='operator'/></cell>
    </row>

    <row>
      <cell><JButton id='d0'     label='0' onActionPerformed='digit(0)' styleClass='digit'/></cell>
      <cell><JButton id='sign'   label='+/-' onActionPerformed='toggleSign()' styleClass='operator'/></cell>
      <cell><JButton id='dot'    label='.' onActionPerformed='dot()' styleClass='digit'/></cell>
      <cell><JButton id='divide' label='&#x00F7;' onActionPerformed='divide()' styleClass='operator'/></cell>
    </row>
  </Table>
</Application>

The code that does all of the math is in a separate file, Calculator.script, which isn't relevant here. Hopefully this example is pretty easy to read even if you have never seen JAXX before. It's just creating a label, a bunch of buttons, and sticking them into a table. As it appears above, there is no style information at all -- no in-line styles, no stylesheet. Just plain raw components:

Calculator-unstyled.gif

Clearly, it needs some work. Let's start by adding a style tag:

<Application title='Calculator'>
  <style source='Calculator.css'/>
  <script source='Calculator.script'/>
...
</Application>

Now we need to create the Calculator.css file:

Application {
    lookAndFeel: system;
}

#display {
    background: #BCE5AD;
    opaque: true;
    horizontalAlignment: right;
    border: {BorderFactory.createBevelBorder(BevelBorder.LOWERED)};
    font-size: 22;
    font-weight: bold;
}

This stylesheet switches the look and feel to "system" (Microsoft Windows on this particular machine) and styles the component named "display" to have a background, a border, and different font settings. Here's what it looks like now:

Calculator-step1.gif

We're headed in the right direction now, but it needs more. Perhaps a bit of color, maybe some bigger buttons, different font...

Application {
    lookAndFeel: system;
}

#table {
    border: {BorderFactory.createEmptyBorder(4, 4, 4, 4)};
    font-face: "Trebuchet MS";
}

#display {
    background: #BCE5AD;
    opaque: true;
    horizontalAlignment: right;
    border: {BorderFactory.createBevelBorder(BevelBorder.LOWERED)};
    font-size: 22;
    font-weight: bold;
}

JButton {
    font-size: 18;
    width: 60;
    height: 35;
}

JButton.digit {
    foreground: blue;
}

JButton#dot {
    font-size: 20;
}

JButton.operator {
    font-size: 18;
    foreground: #009900;
}

JButton.clear {
    foreground: red;
}

This stylesheet controls the buttons based on their styleClass attributes, and in one case id, in order to style them by logical groupings. Here is the calculator with the final stylesheet in place:

Calculator-styled.gif

Compare the newly styled appearance against the unstyled appearance above. Okay, so it's not Monet, but I'm not a UI designer either. The fact that I could hand this program and this stylesheet to a UI designer and say "please make this prettier" -- and that the UI designer would actually be able to without my help -- is really exciting to me. I think CSS stylesheets and Swing are a perfect marriage, and I'm pleased with how the combination has turned out in JAXX.

If you want to compile and run these examples yourself, you will need to download JAXX from http://www.jaxxframework.org/.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Hi Ethan, Great example. For those of us who prefer not to describe our guis in xml, but in code, but would prefer to externalise styles this would seem to work really well. Is it possible to use the styling ability with normal swing classes? Perhaps this effort should be externalised and coordinated along with fuse? Joe

    Posted by: profiler on March 25, 2006 at 06:10 AM

  • I agree that it would be great to have CSS available outside of the context of JAXX, but JAXX's particular CSS engine wouldn't be much help -- JAXX is a compiler, so all of its CSS styles are applied at compile time. A CSS engine which worked with normal Java code would have to be able to apply styles at runtime, which requires completely different approaches to doing things (and an awful lot of reflection). - Ethan

    Posted by: enicholas on March 25, 2006 at 07:19 AM

  • The CSS looks incredibly elegant. The need for compiling is a drawback; would be nice to be able to change the CSS for live applications. I've helped out with the XHTMLRenderer project here on java.net and one of the developers there developed a nice CSS matching routine (for XML), I worked on some of the cascading/inheritance logic. Might be an opportunity somewhere to bring the two ideas together. Anyway--great blog presentation, the idea was well presented. Good work! Patrick

    Posted by: pdoubleya on March 26, 2006 at 04:29 AM

  • Actually we've been tinking about having a CSS syntax for Fuse ever since I started the project. I would like to take a closer look at JAXX to see whether we can leverage part of the existing code. I was also thinking this could be very useful with Synth. I would love to be able to write this: JToolBar > JLabel { ... } To style the JLabels contained in a toolbar.

    Posted by: gfx on March 27, 2006 at 01:15 AM

  • While the technical aspects of this are fine, the notion that you can throw together an application without considering user interaction at all and then hand it off to a "UI designer" and have them make it "prettier" is the sort of attitude that leads to the dreadful programmer-centric interfaces people have been struggling with since the begining of the computer era.

    Posted by: rlinwood on March 27, 2006 at 04:51 AM

  • Hi Ethan --

    Another thing you might consider is the ability to take behavior out of your structural markup -- have a behaviors file that uses CSS selectors to assign scripts to widgets, rather than having that assignment made in the widget markup itself.

    You can see an example of this for HTML markup with JavaScript Event Sheets

    Posted by: erickson on March 27, 2006 at 09:19 AM

  • You can already do that in a lot of cases (I'll go into more advanced stuff in my next post). For instance "JButton:mouseover { foreground: blue; }" causes buttons to turn blue when moused over. I suspect that this sort of usage covers 95% of the desired cases -- did you have specific usages in mind? - Ethan

    Posted by: enicholas on March 27, 2006 at 09:34 AM

  • A good direction for gui styling... This is something Macromedia Flash components have had for awhile, although from what I remember, the support was flaky here and there.

    Posted by: ilazarte on March 27, 2006 at 11:08 PM

  • JAXX is a compiler, so all of its CSS styles are applied at compile time. seo.A CSS engine which worked with normal Java code would have to be able to apply styles at runtime, which requires completely different approaches to doing things.

    Posted by: stillstayhere on February 26, 2008 at 07:32 PM

  • Hi, I would like just tell about my work about my CSS Engine. My CSS Engien can manage CSS Style sheet (with w3c object like CSSValue, CSSStyleDecklaration) and you can apply style (at runtime) for Swing or SWT widgets. You can manage selector (with Swing class like JTextField {color:red;} or HTML name like input[type=text] {color:red;}) You can manage dynamic pseudos classes like JTextField:focus{color:red} You can add your own CSS Property... If you are intereted you can download Eclipse projects : http://tk-ui.svn.sourceforge.net/svnroot/tk-ui/org.akrogen.tkui.css/trunk/org.akrogen.tkui.css.core => CoreCSS Engine And http://tk-ui.svn.sourceforge.net/svnroot/tk-ui/org.akrogen.tkui.css/trunk/org.akrogen.tkui.css.swt => SWT CSS Engine implementation For Swing, it's not finished but you can test it with project http://tk-ui.svn.sourceforge.net/svnroot/tk-ui/org.akrogen.tkui.css/trunk/org.akrogen.tkui.css.swing => Swing CSS Engine implementation You can fins frensh documentation into the docs folder of the project org.akrogen.tkui.css.core This CSS Engien will be used for my TK-UI project http://tk-ui.sourceforge.net/ (describe your UI with XML (XUL, XHTML, XForms....) and renderer it into Swing or SWT. You can contact me if you want more explanation about CSS Engine. Regards Angelo

    Posted by: azerr on April 22, 2008 at 08:26 AM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds