Advanced Synth

Custom UIs are a breeze with the newest Swing look and feel

Take an in-depth look at the Synth look and feel, the newest addition to Swing introduced in Java 5.0. Synth lets developers rapidly create and deploy custom looks for an application by introducing the concept of a "skin" to Java UI programming. Software Engineer Michael Abernethy takes you through Synth concepts step-by-step to build an application with a Synth look from scratch. After reading this article, you should be able to create professional-looking UIs in no time.

Michael Abernethy, Software Engineer, IBM, Software Group

Michael Abernethy works as a lead in the WebSphere System Management Functional Test Team. He worked previously in the WebSphere Services team for four years, writing and deploying enterprise applications on WebSphere. He dabbles in Swing and UI development in his free time.



01 February 2005

Also available in Japanese

Even as Sun continues its attempt to "reintroduce the Java Desktop," one complaint keeps surfacing from Java UI developers: It's far too difficult to create a complete custom look and feel. Not only is the effort too time consuming, but the Swing UI code is poorly written and poorly documented, often looking hacked together and badly planned. Creating a complete look and feel has required developers to subclass either the Metal look and feel's 39 classes or the Basic look and feel's 60 classes. Who the heck wants to override an entire package to change the way an application looks? Another sure indicator of how difficult it is to create a custom look and feel in Swing is that in an age when many developers donate their hard work for free to open source projects, barely any custom Swing look and feels are available on the Internet -- about 20 in all, including only a handful on SourceForge.net (see Resources).

Beauty's only skin deep

Enter Synth, which Sun hopes will ease the process of personalizing an application's look. The goal for Synth is simple -- let developers create a new look and feel without writing one line of Java code. This seems like a good solution. Programmers in general aren't known as the most artistic of people, and graphic artists aren't generally experts on Java coding. Synth provides a happy compromise by removing the entire description of the look from the code and placing it in an external XML file and image files. This type of look and feel, one that's described solely in external files, is called a skin.

Sun isn't breaking any new ground with the idea of a skin. Hundreds of skins exist for Winamp and dozens for Firefox, for example, because they're simple to create with only an XML file to change. Imagine creating a look and feel quickly and easily for a Java application by simply modifying an XML file. And then imagine the possible results -- hundreds of unique Swing look and feels. Java UI developers have reason to celebrate.

This article digs deeply into the Synth look and feel. I'll show you everything you need to know to create a complete look or skin. You'll examine a sample skinned application that uses all of Synth's important concepts. Then I'll break the skin down step-by-step to teach you Synth concepts as you build the XML file.

The article's last section attempts to answer many of the questions that developers have about Synth performance, bugs and defects, and the time savings that Synth offers. After reading this article, you should be willing to embrace Synth as a look and feel solution and be ready to use it to create your own skins for Swing in no time.


Synth basics

Synth is a tabula rasa look -- a completely blank canvas that appears as an all-white panel until some components are defined in the XML file. Once you define the components, setting the Synth look and feel on an application couldn't be easier, as you can see in Listing 1:

Listing 1. Setting the Synth look and feel
   SynthLookAndFeel synth = new SynthLookAndFeel();
   synth.load(SynthFrame.class.getResourceAsStream("demo.xml"), SynthFrame.class);
   UIManager.setLookAndFeel(synth);

But with Synth it's the XML code, not the Java code, that's most important to understand. Although the Synth XML format initially seems difficult and intimidating, it's really rather straightforward. If you use the KISS (Keep It Simple Stupid) mantra, you can quickly create an XML file and get a new look and feel up and running.

With the KISS directive in mind, I'll start by introducing the main building block of the Synth XML file -- the <style> tag. The <style> tag contains all the information needed to describe a component's style, such as the colors, fonts, image files, states, and component-specific properties. Although a single <style> tag can describe more than one component, the easiest way to build a Synth file is to create a style for each individual Swing component.

Once you finish creating the style, you link the style to a component. The <bind> tag tells the Synth engine to link a defined style to a component, as in Listing 2. This combination completely creates the component's new look.

Listing 2. Linking one style to one component
<style id="textfield">
   // describe colors, fonts, and states
</style>
<bind style="textfield" type="region" key="Textfield"/>

<style id="button">
   // describe colors, fonts, and states
</style>
<bind style="button" type="region" key="Button"/>

One note about the <bind> tag: The key attribute inside the <bind> tag maps to constants in the javax.swing.plaf.synth.Region class. The Synth engine uses these constants to link the style with an actual Swing component. Simple components, such as JButton and JTextField, use one constant. Some more-complex components, such as the JScrollBar and the JTabbedPane, have multiple constants for their different parts.

I recommend using the one-style-per-component setup until you are more familiar with the Synth format and can set up inheritance models in the XML. This structure doesn't take advantage of all of XML's hierarchical capabilities, but it's the most straightforward to set up, code, and debug.

Another important point to remember when dealing with the Synth XML file is that it doesn't validate anything. If you make typographical errors or use incorrect attributes in the XML, your mistake won't show up until a runtime exception is thrown when the look and feel is loaded. Translation: Test the XML file before you ship it to a customer.


Demo application

I'll walk you through building a simple login screen as an example application to show you how a Synth XML file works. The screen provides enough components that you can see all the important parts of the XML file and how they come together to create an entire look and feel.

As you can see by comparing Figures 1 and 2, the login screen in the Ocean look and feel looks as you might expect -- simple, straightforward, and boring. The login screen in the Synth look and feel is completely different.

Figure 1. Demo application with Ocean look and feel
Ocean look and feel
Figure 2. Demo application with Synth look and feel
Synth look and feel

Changing a color and font

The first step in creating the look and feel for the demo application is to set the default colors and fonts. You'll make the white Aharoni font the default font for every component that doesn't specifically set it otherwise.

You can place the XML to change a font anywhere inside the <style> tag. You embed the color inside a <state> tag. I'll discuss the <state> tag more later in this article, but it's enough to understand now that a simple <state></state> tag with no attributes encompasses every state, which is what you need here.

The color tag itself requires two attributes:

  • value can be any String representation of the java.awt.Color constants (for example, RED, BLUE), or it can be the hex representation of a color preceded by a "#" (for example, #669966).
  • type describes which area's color the file should set. The choices are BACKGROUND, FOREGROUND, TEXT_FOREGROUND, TEXT_BACKGROUND, and FOCUS.

The font tag has two required attributes and one optional one. They map directly to the three parameters in the java.awt.Font class:

  • name: The font's name (for example, Verdana, Arial).
  • size:The size in pixels.
  • style: Leaving out this optional tag results in a normal-looking font. Other options include BOLD and ITALIC. You can also specify a bold italic font by putting a space between the two attributes: BOLD ITALIC. (This technique for combining attributes holds true for all attributes in the Synth XML file.)

Finally, instead of binding this style to each JLabel and each JButton, you can bind it to every component in the application, by using the .* wildcard. This wildcard tells the Synth look and feel to give every component a default white Aharoni font. Listing 3 shows the complete XML code for setting the components' font and color:

Listing 3. Changing multiple components' fonts and colors
<style id="default">
   <font name="Aharoni" size="14"/>
   <state>
      <color value="#FFFFFF" type="FOREGROUND"/>
   </state>
</style>
<bind style="default" type="region" key=".*"/>

Using images

The textfield borders in Figure 2 aren't normal-looking single-pixel rectangular borders. You create them by using an image. This isn't an unfamiliar concept -- images have been used in buttons and labels for a while now -- but you can imagine where some issues will come up. How does the cursor know where to go, how does the text get painted, and how do you create different-sized text fields? These issues are addressed by the concept of image stretching. One image file must describe every size of text field in the application, so you need a way to tell the XML file how to stretch the image properly and how to handle the normal textfield activities (carat and text control).

Luckily, a method of doing this type of stretching has been available since the early skinned applications. The image must be divided into nine regions -- top, top right, right, bottom right, bottom, bottom left, left, top left, and center -- that you specify by an attribute in the XML file. The renderer can then stretch the image in a certain way to fit the allotted space. Figure 3 shows how the text-field image stretches.

Figure 3. How an image gets stretched in Synth
Synth look and feel

The green-tinted regions in Figure 3 will only stretch in the vertical; that is, they'll grow when the text field is taller than the image. The red-tinted regions will only stretch horizontally, when the text field is longer than the image. The regions tinted yellow will not grow at all. No matter how big the text field gets, these regions will be drawn exactly as they look in the image file. Because these regions won't be stretched, they should contain all the curves, special tinting, shadows, and anything that would look odd if it were stretched out. Finally, the center region is optional. You can specify either to either draw or to omit it. The text field's center is omitted in our example. The renderer then uses this region to handle the text control and the carat. That's it -- the text field is completely drawn using a single image file.

The imagePainter tag provides all the information needed to use images in the look and feel. It requires only a few attributes:

  • path: The path to the image to be used.
  • sourceInsets: The insets in pixels, representing the width of the green areas and the height of the pink areas in Figure 3. They map to the top, left, bottom, and right, in that order.
  • method: This is perhaps the most confusing attribute. It maps directly to a function in the javax.swing.plaf.synth.SynthPainter class. The class contains about 100 functions, all of them starting with paint. Each function maps to a specific painting job in a Swing component. You just need to find the right one, then set the attribute by removing the paint string and lowercasing the first letter after it. For example, paintTextFieldBorder is the attribute of textFieldBorder. The renderer takes care of the rest.
  • paintCenter: This attribute lets you keep the center of an image (in a button for example) or get rid of it. The textfield in the example gets rid of it to allow text to be drawn.

The final step in using an image to paint borders is to increase the default insets to handle the new image you are using to draw them. If you don't change the insets, no image at all will be visible. You need to add an <insets> tag to increase the insets so the image can be painted in them. In most cases, the insets' values should be identical to those of the insets you used in the image.

Listing 4 shows the XML code for loading images. Notice how the sourceInsets ensure that only the proper parts of the image get stretched.

Listing 4. Loading images
<style id="textfield">
   <opaque value="true"/>
   <state>
      <font name="Aharoni" size="14"/>
      <color value="#D2DFF2" type="BACKGROUND"/>
      <color value="#000000" type="TEXT_FOREGROUND"/>
   </state>
   <imagePainter method="textFieldBorder" path="images/textfield.png"
      sourceInsets="4 6 4 6" paintCenter="false"/>
   <insets top="4" left="6" bottom="4" right="6"/>
</style>
<bind style="textfield" type="region" key="TextField"/>

Handling different states

As you've seen from the examples so far, the <state> tag is a major focal point of defining a component. In Listings 3 and 4, color and font tags are inside the <state> tag. Now I'll explain what the <state> tag does.

The default state, where no attribute is specified in the <state> tag, is sufficient for defining the colors and fonts in a text field and in labels, because their states won't change. But in a component whose state will change -- a button, for example -- you can define a completely different look for every state. Each state can have its own colors, fonts, and images. Compare the login screen's Cancel button in its default state (Figure 4) to its mouse-over state (Figure 5).

Figure 4. Cancel button in DEFAULT state
Default State
Figure 5. Cancel button in MOUSE_OVER state
Mouse over state

The <state> tag requires only a value attribute, which defines the actual component state. If you don't specify a value, as in Listings 3 and 4, the default applies to every state. If you specify the value attribute, your choices are ENABLED, MOUSE_OVER, PRESSED, DISABLED, FOCUSED, SELECTED, and DEFAULT. These choices cover all of the possible states of any component in Swing. You can also combine states by adding an and between them. For example, if you want to change fonts on a button when the mouse is over it and the button is pressed, you use a state value of MOUSE_OVER and PRESSED.

Listing 5 shows the XML for handling the demo application's states. Notice how each state defines a different image and text color.

Listing 5. Handling states
<style id="button">
   <state>
      <imagePainter method="buttonBackground" path="images/button.png"
         sourceInsets="9 10 9 12" paintCenter="true" stretch="true"/>
      <insets top="9" left="10" bottom="9" right="12"/>
      <font name="Aharoni" size="16"/>
      <color type="TEXT_FOREGROUND" value="#FFFFFF"/>
   </state>
   <state value="MOUSE_OVER">
      <imagePainter method="buttonBackground" path="images/button_on.png"
         sourceInsets="9 10 9 12" paintCenter="true" stretch="true"/>
      <insets top="9" left="10" bottom="9" right="12"/>
      <color type="TEXT_FOREGROUND" value="#FFFFFF"/>
   </state>
   <state value="PRESSED">
      <imagePainter method="buttonBackground" path="images/button_press.png"
         sourceInsets="10 12 8 9" paintCenter="true" stretch="true"/>
      <insets top="10" left="12" bottom="8" right="9"/>
      <color type="TEXT_FOREGROUND" value="#FFFFFF"/>
   </state>
   <property key="Button.margin" type="insets" value="0 0 0 0"/>
</style>
<bind style="button" type="region" key="Button"/>

An important aspect of dealing with the <state> tag is knowing which components go with which states. Obviously, in this example, buttons can have a default state, a mouse-over state, and a pressed state. You could also define a focused and a disabled state for the example. But with a panel, for example, selected doesn't even apply, and changing a panel's state on a mouse-over would be just plain annoying.


Dealing with component-specific properties

Defining XML attributes that are general enough for every component will always leave some component-specific properties out. Examples include a list's row height, a radio button's icon, and a menu's arrow icon. There are more than 100 component-specific properties that could be defined, but defining an XML attribute for each one would be excessive. So, the Synth XML file lets you set component-specific properties. The <property> tag works like a Hashtable, defining a key/value pairing to set the properties.

The login-screen example's checkbox demonstrates how to code component-specific properties. By defining imageIcons, you can set the CheckBox.icon property in both the default state and the selected state. It's as simple as that -- well, as simple as sorting through a list of 100 properties to find the ones you want.

Listing 6 shows the XML for coding component-specific properties for the login screen. Notice that you define the imageIcon first. Then, by using the image icon's ID, you can set an icon for each of the checkbox's states.

Listing 6. Defining component-specific properties
<style id="checkbox">
   <imageIcon id="check_off" path="images/checkbox_off.png"/>
   <imageIcon id="check_on" path="images/checkbox_on.png"/>
   <property key="CheckBox.icon" value="check_off"/>
   <state value="SELECTED">
      <property key="CheckBox.icon" value="check_on"/>
   </state>
</style>
<bind style="checkbox" type="region" key="Checkbox"/>

Working with custom painters

The final piece to defining the example login screen in Figure 2 is to draw the gradient background with the curved line. This probably looks tough to do in XML, and frankly it is. But it gives me a chance to show that Synth doesn't limit you to using only images and simple colors in UI designs. You can use it to draw anything.

Synth lets you override its paint methods (the ones in javax.swing.plaf.synth.SynthPainter) by subclassing SynthPainter and overriding only the specific functions you wish to custom paint. In the example, you need to custom paint the paintPanelBackground method, because the design can't be described in the Synth XML format.

To use a custom painter, or to create a class in any way in the XML, you use the <object> tag. The <object> tag allows for creation and persistence of any Java classes you want to use to supplement the Synth rendering. The <object> tag takes two elements:

  • class: The full name of the class that should be created
  • id: The ID name you'll use to reference this class instance in the XML document

By using objects, you not only can create the instance of the BackgroundPainter class -- the class that will paint the background. You can also create an instance of a ColorUIResource class, where you define the background colors. Think about it: Defining the colors used in the background inside the BackgroundPainter class itself would contradict Synth's goal of defining everything in an external XML file rather than hard-coding it in a Java file.

The final step to using a custom painter is to tell the Synth rendering engine that you, not the SynthPainter class, will be supplying the function. In the example, you define the paintPanelBackground function in the BackgroundPainter class and let Synth use its SynthPainter class to define the rest of the paint functions. The <painter> tag lets you override the SynthPainter function. It takes two elements:

  • method: The method that the custom painter should override. As you know from Using images, you can find these functions in the javax.swing.plaf.synth.SynthPainter class but should remove the paint string at the beginning of each function. (So paintPanelBackground in SynthPainter should be panelBackground in the XML file, for example.)
  • id: The reference to the class that will override the method.

In order to use the colors in the custom painter, you must store them in the javax.swing.UIDefaults class. As you can see in Listings 7 and 8, storing colors in UIDefaults is straightforward and should be familiar to anyone who's worked with UI creation. The key you define in the XML will be the reference in the UIManager you use to get the colors in the actual Java code for BackgroundPainter.

Listing 7 shows the XML code for working with custom painters in the example application. Notice that you must define the colors first.

Listing 7. Working with custom painters
<style id="panel">
   <object id="background" class="demo.synth.BackgroundPainter"/>
   <object class="javax.swing.plaf.ColorUIResource" id="startColor">
      <int>30</int>
      <int>123</int>
      <int>235</int>
   </object>
   <defaultsProperty key="Panel.startBackground" type="idref" value="startColor"/>
   <object class="javax.swing.plaf.ColorUIResource" id="endColor">
      <int>1</int>
      <int>20</int>
      <int>80</int>
   </object>
   <defaultsProperty key="Panel.endBackground" type="idref" value="endColor"/>
   <painter method="panelBackground" idref="background"/>
</style>
<bind style="panel" type="region" key="Panel"/>

Listing 8 shows the Java code for the example application's custom-painting class:

Listing 8. Java code for custom painting
public class BackgroundPainter extends SynthPainter
{

   public void paintPanelBackground(SynthContext context,
                                    Graphics g, int x, int y,
                                    int w, int h)
   {
      Color start = UIManager.getColor("Panel.startBackground");
      Color end = UIManager.getColor("Panel.endBackground");
      Graphics2D g2 = (Graphics2D)g;
      GradientPaint grPaint = new GradientPaint(
          (float)x, (float)y, start,
          (float)w, (float)h, end);
      g2.setPaint(grPaint);
      g2.fillRect(x, y, w, h);
      g2.setPaint(null);
      g2.setColor(new Color(255, 255, 255, 120));
      g2.setRenderingHint(
          RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      CubicCurve2D.Double arc2d = new CubicCurve2D.Double(
          0, h/4, w/3, h/10, 66 * w, 1.5 * h, w, h/8);
      g2.draw(arc2d);
      g2.setRenderingHint(
      RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
   }
}

More-advanced settings

This section covers a couple of techniques that go beyond those you've seen in the login-screen example. You might find them useful in creating your own Synth looks.

Painting non-Swing components

Being able to change the look of every Swing component is great, but Synth also needs to be able to change the look of other components -- ones developers have created to fill the gaps left by Swing. In such cases, the <bind> tag needs to change to reflect that a Swing component isn't being painted. The type attribute can have two values -- region if it is being mapped to a Swing component, and name if it is being mapped to a non-Swing component. So, changing the <bind> tag to <bind style="mystyle" type="name" key="Custom.*"/> will change every component whose class name starts with Custom (for example, CustomTextField or CustomLabel) to use the mystyle style.

Hierarchies of styles

Breaking from the KISS style of creating the XML file, you can also build a hierarchy of styles and apply them to components. Listing 9 should make this clear. Note that Synth uses the attribute that was defined last to render the component.

Listing 9. Example of hierarchies
   <style id="base">
      <color value="BLACK" type="BACKGROUND"/>
      <state>
         <font size="14"/>
      </state>
   </style>
   <bind style="base" type="region" key=".*"/>

   <style id="sublevel" clone="base">
      <color value="RED" type="BACKGROUND"/>
   </style>
   <bind style="sublevel" type="region" key="Label"/>

The code in Listing 9 gives every component a black background with a font size of 14 except labels, which have a red background. By cloning the base style in sublevel, it copies the entire style. You can then override any specific properties that you need to.


Examining Synth performance, reliability, and efficiency

Now that you've seen how to create an XML file for Synth and how to create a custom look by changing fonts, changing colors, and adding images, you probably have questions about Synth. If you've dealt with Swing for a while now, I'm sure you first thought about performance issues. I've devised some performance tests that show that Synth won't slow your UI to a crawl. I've also checked out the Java Bug Parade (see Resources) for Synth issues to investigate problem areas you might see (and to discuss issues I've come across in working with it). Finally, I'll answer your most important question -- will Synth really save you time?

Does loading so many images make Synth slower?

I've created two tests to answer this question and give you a better feel for how Synth stacks up against the other look and feels in terms of performance. The first test times the load-up for the example login-screen application. This test loads six images in Synth and compares the load-up time to that of an average screen that a developer might create. The second test is a stress test on load-up times -- a frame with over 100 components.

Both tests time the Ocean and Motif look and feels for comparison. To make a fair evaluation, I ran both tests on three machines -- a Windows XP laptop, a SuSE Linux box, and a Red Hat Linux box. The results appear in Tables 1 and 2.

Table 1. Average load time of login screen
Machine settingsOceanMotifSynth
Windows XP - 1.7GHz - 2GB RAM.32 seconds.29 seconds.57 seconds
SuSE Linux 9.0 - 3.3GHz - 2GB RAM.23 seconds.20 seconds.45 seconds
Red Hat Linux 3.0 - 1.4GHz - 512MB RAM.37 seconds.32 seconds.61 seconds
Table 2. Average load time of 100-component screen
Machine settingsOceanMotifSynth
Windows XP - 1.7GHz - 2GB RAM.33 seconds.32 seconds.34 seconds
SuSE Linux 9.0 - 3.3GHz - 2GB RAM.23 seconds.23 seconds.30 seconds
Red Hat Linux 3.0 - 1.4GHz - 512MB RAM.40 seconds.40 seconds.43 seconds

As you can see, the Synth look and feel loads up only minimally more slowly than Ocean and Motif. Note, though, that the login screen loads up more slowly than the stress test. This seems odd at first glance, but closer examination revealed the culprit. The stress test doesn't load the images used in the checkbox, whereas the login screen does. This leads to the conclusion that every additional image used in the Synth look adds to load up time. A hundred components using the same image will load faster than an application that has two components using two images. Reducing the number of images used will improve performance in Synth load-up times.

Is Synth as buggy as Swing was when it was first released?

To judge by the Bug Parade on Sun's Java developer Web site, Synth seems to be a clean and bug-free product. However, no software is perfect. At one point there were 125 bugs against Synth, a disproportionate share of which related to how Synth deals with the JTabbedPane. So if you experience some issues there, don't be surprised. In Sun's defense, though, these defects are all in the "Closed" state. But it's often the case that if there have been problems before, problems will probably occur in the future.

Despite the relatively clean image that the bug database gives Synth, I had some other issues when working with the login screen. My first attempt at changing the background color of the JPanel failed. I had created a style specific for JPanels and bound it to all JPanels, but it just didn't work. Things did work when I decided to use my own custom painter instead.

A bigger issue is the repainting of the widgets when states change. In working with the buttons and their states, I found that the text on the button wouldn't change colors properly. The default color of white would not appear correctly when initialized and wouldn't show up until a state change had been triggered and then was set back to default. Poring through the documentation on Synth turns up this little tidbit: "While you can supply a different font per state, in general widgets will NOT revalidate when the state changes, so that you may run into sizing problems if you try to use a font with a significantly different size for different states." Sounds like they ran into problems trying to make Synth work with the old legacy Swing code. So, beware when trying to change fonts when states change.

Synth does appear to be relatively bug free. But I wouldn't be surprised if little things crop up here and there where the code should work but doesn't. Workarounds shouldn't be hard to find, though. I could find one for every issue that popped up in my work.

Can a complete professional look and feel be created from Synth?

The answer is yes. The GTK+ and Windows XP look and feels released in Java 1.4 were created solely by using Synth. (It wasn't a published API back then.) So it definitely can be done.

How much faster can you create a complete look with Synth versus writing one in Java code?

This should be easy to compute. Two steps are involved in each approach:

  1. Creating the look, which is work usually done by graphic artists
  2. Converting the graphical work into code

In both the Java-coding and Synth approaches, the graphic-design work takes the same amount of time. Based on my experience in creating custom looks, I estimate that graphic artists take about two people two weeks to create a complete look for an application. That's four person-weeks for graphical work.

Again, based on my experience, it takes three Java coders about two months to translate graphical drawings to a complete, ready-for-prime-time look and feel through subclassing. That's six person-months of Java coding. Adding on the graphical work, it takes seven person-months to create a complete custom look and feel in Swing by overriding the UI classes. Numbers like these help you see why there are so few available for download on the Internet.

Synth enables huge time savings by translating the graphical work to an XML file. The six person-months it takes to create a look by Java coding becomes only two weeks for one developer to translate the graphical work into a Synth XML file. That takes the total down to only six person-weeks to create a complete look and feel in Synth -- more than five months of time savings by using Synth. With a team of two graphical designers and two programmers, a complete Synth look could be produced in just three weeks.


Conclusion

Synth brings the concept of skins to Swing. Synth's biggest advantage over the traditional method of writing a custom look and feel in Java code is its time savings. An entire Swing look can be created in less than a month, five times more quickly than it takes to code it in the Java language. Or for the ambitious developer, five Synth looks can be created instead of just one Java-coded look.

However, not everything is perfect in the world of Synth. Writing Java code to override the Swing look lets you completely change both the look and feel of an application. Synth only lets you change its look. This is a significant difference. The look is just that -- the colors, fonts, and images used in the application. The feel, on the other hand, corresponds to the behavior that the application shows during interaction -- a right mouse click here, a key press there. For example, if you want to change the behavior of a JList to select items with a left mouse click, and delete them with a right mouse click, you can't do it with Synth. You'd need to write Java code for a new look and feel. Synth should really be called a new Swing look, not a look and feel. You can change a UI's look quickly with Synth, but the feel will always be the default Swing feel.

Still, if you want to spruce up your application by giving it a new look, or have longed to see a Swing application look better than the putrid Metal look -- thank goodness that's history with Java 5.0 -- Synth is a great option. It offers no performance issues and seems relatively bug free. And Sun has already shown that a complete look can be created with Synth by releasing the GTK+ look.

Synth documentation and examples are surprisingly scarce now. Having read this article, you should have a deeper understanding of how Synth works and be able to generate a complete Synth XML document using the one-style-tag-per-one-component design. Synth's inheritance and hierarchy models offer more powerful ways to create style tags, but you can create a complete look without them. Ideally, as Synth knowledge grows, the Swing UI community will begin to see an explosion in the number of skins. With potentially hundreds of looks to choose from, the labels often attached to Swing apps of "horrible looking" and "ugly" -- I don't think I'm being too harsh -- will disappear forever.


Download

DescriptionNameSize
Code samplesynth.jar21 KB

Resources

  • Be sure to read the Synth Javadoc.
  • The Synth File Format documentation offers a complete look at all the possibilities in a Synth XML file.
  • The Synth Component Specific Properties documentation lists the more than 100 component specific-properties that can be set in the XML files.
  • The Region class documentation lists all the Swing components and parts of components that can be changed in the Synth XML file.
  • The SynthPainter class documentation lists all the functions that can be described in the imagePainter and painter tags.
  • Custom Swing look and feel projects on SourceForge include the Liquid, Napkin, oyoaha, Skin, GTK+ Pluggable, Vira, and Office look and feels.
  • "Ocean and Synth meet Metal" (developerWorks, October 2004) in John Zukowski's Taming Tiger series explores Ocean and Synth, the new look and feels in Java 5.0.
  • "The Synth Look and Feel " by Scott Violet is Sun's original presentation on Synth, dating back to its introduction in early 2004.
  • Visit the searchable Java Bug Database (a.k.a. the Java Bug Parade).
  • You'll find articles about every aspect of Java programming in the developerWorks Java technology zone.
  • Browse for books on these and other technical topics.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Java technology on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=33529
ArticleTitle=Advanced Synth
publish-date=02012005