The Source for Java Technology Collaboration
User: Password:



Romain Guy's Blog

September 2005 Archives


NetBeans 5.0 beta and its profiler

Posted by gfx on September 30, 2005 at 01:31 PM | Permalink | Comments (4)

I remember a great presentation of NetBeans profiler during NetBeans Day before JavaOne 2005 and I know I wanted to try it ever since. I finally did with the release of NetBeans 5.0 beta and I know I'll use it a lot. If you follow my blogs you know I spend a lot of time writing heavy Swing/Java2D effects. That's why I could really use a good graphical profiler to help me spot performance bottlenecks in my code. I usually rely on System.currenTimeMillis() but it's rather tedious and somehow useful only when you already suspect a piece of code to be the culprit.

NetBeans Profiler may not be as extensive as, say, JProfiler or other dedicated tools. Nevertheless, it addresses my needs and provides me an effective and straightforward UI to quickly spot heavy CPU or memory usages. The feature I love the most is the ability to monitor and analyse an application running outside of NetBeans. This allows me to start old projects or projects I run in Eclipse and monitor them in NetBeans Profiler. I guess I will start using NetBeans a bit more to benefit from the Profiler's capacity to monitor only a fragment of your code.


And as you can see on the screenshot, the UI looks really great on my Windows XP box, especially on Mustang with the subpixel antialiasing.



Why should I choose only one IDE?

Posted by gfx on September 30, 2005 at 10:47 AM | Permalink | Comments (1)

As many programmers I don't like using an IDE. Well, at least I used to. I spent many years using an editor of my own and it served my purpose very well. Hey, after all I wrote it according to my needs. Apart from Jext I always used Metapad on Windows, a slightly improved clone of Notepad, and vim on other platforms. Convinced IDE could boost my productivity, I decided to seriously try to use them about two years ago. At this time I settled my choice on NetBeans, which I liked it. Eclipse was too confusing for me and I really hated its project management. Anyway, 6 months later I insisted on using Eclipse and I loved it ever since. For two reasons: refactoring (which completly changed the way I code) and quick fixes. About 4 months ago I decided to attempt a switch to IntelliJ IDEA and it almost worked. But despite very very cool features, I still preferred Eclipse for most common operations, faster and easier to perform IMHO. So, after one month of IDEA I went back to Eclipse.

Yet, I might really drift away from Eclipse very soon. Or I will at least use two IDE on a daily basis instead of one. There are some issues that drive me crazy in Eclipse, like plugin management, workspaces preferences and crashes in some specific cases (I spent two hours this week trying to import my preferences from Eclipse 3.1 to Eclipse 3.2 without crashing the whole JVM). I have to admit that NetBeans 5.0 seems really attractive to me. It sure is far from providing all the features I'm using in Eclipse (quick fixes, how could I live without you) but it's closing the gap.

As I said may times, I really dig Matisse. But yesterday I finally tried the Profiler and I just love it. It's clean, simple and easy to use. Best of all, I can even use it with projects not running into NetBeans itself. That stuff just rocks. I also love the fact projects are based upon Ant. I'm not ready to drop Eclipse yet but I will definitely use both Eclipse and NetBeans from now on. One to increase productivity when writin miles of code, the other one to increase productivity when debugging (well, profiling) and designing UI.

Who said I have to use only one IDE?

P.S: So now I'm using Eclipse, NetBeans, Jext, Notepad2 and vim on Windows depending on the task at hand. I guess I don't like the idea of using a single versatile tool :))

Synth Subtlety, Style that ComboBox @#!

Posted by gfx on September 28, 2005 at 04:08 PM | Permalink | Comments (14)

Synth can be tricky (JScrollbar) sometimes (JTree). So tricky that I actually fell into a trap today. When styling a combo box, I ran into a rather curious problem. A combo box is made of a popup menu, a list, a label, an arrow button and, in case of editable combo boxes, a text field. Since these components are styled independantly, it can be difficult to give them a specific style when in the combo box.

Usually, components are styled by regions. That means you bind a style to generic region for every component instance, like a ScrollBar which would be styled for scroll panes, text areas, etc. So, what happens when you style your scrollbars and use a combo box? Behold the disaster:


Hopefully, Synth also allows you to style components by name instead of by region:

<style id="arrowStyle">
  <imagePainter method="arrowButtonForeground" path="images/upArrow.png"
   sourceInsets="0 0 0 0" stretch="false" direction="north" />
  <imagePainter method="arrowButtonForeground" path="images/downArrow.png"
   sourceInsets="0 0 0 0" stretch="false" direction="south" />
  <imagePainter method="arrowButtonForeground" path="images/leftArrow.png"
   sourceInsets="0 0 0 0" stretch="false" direction="west" />
  <imagePainter method="arrowButtonForeground" path="images/rightArrow.png"
   sourceInsets="0 0 0 0" stretch="false" direction="east" />
</style>
<bind style="arrowStyle" type="region" key="Arrowbutton" />

<style id="comboArrowStyle">
  <imagePainter method="arrowButtonForeground" path="images/comboboxArrow.png"
   sourceInsets="0 0 0 0" stretch="false" />
</style>
<bind style="comboArrowStyle" type="name" key="ComboBox.arrowButton" />

Oh how delightful to know we solved yet another issue! But wait... no we didn't @!# The combo box still uses scrollbars' arrow button. Try to remove the style called "arrowStyle" and the combo box will be fine but not the scrollbars. Try to change the order of the styles and nothing will change. If you take a closer look at comboArrowStyle, you'll see it doesn't define a direction for the painter. Why should we after all? A combo box as only one arrow button, there's no need to identify it by its direction. Unfortunately, Synth will internally merge both styles and, at rendering time, it will pick the most specific painter, the one with a direction. That's right, it will pick the painter from the region.

Hence, the final solution is very simple:

<style id="comboArrowStyle">
  <imagePainter method="arrowButtonForeground" path="images/comboboxArrow.png"
   sourceInsets="0 0 0 0" stretch="false" direction="south" />
</style>
<bind style="comboArrowStyle" type="name" key="ComboBox.arrowButton" />

We finally have the appropriate result:




Physics Laws in Swing Applications

Posted by gfx on September 27, 2005 at 04:09 PM | Permalink | Comments (8)

I just finished (well almost) a Swing demo using real world physics to animate a drag and drop gesture. You can try the demo or read more about its implementation. If you're very curious you can also read the source code. Finally, here are two screenshots from the demo:





Native Look? I'm puzzled...

Posted by gfx on September 26, 2005 at 06:58 PM | Permalink | Comments (5)

Important update: R. J. Lorimer has the solution!. Be damned you stupid manifest files! :)

Disclaimer: It's not in my intent to start another flame war about IDE. Also please note that, as a user, I don't care about native look fidelity. Finally, please, please understand that I' talking about the look only, not the feel.

Every now and then, when I read articles about why SWT and/or Eclipse are better than Swing and/or NetBeans, I see the same argument: look and feel fidelity is better. I love Eclipse, I don't like to program with SWT and I have to admit that the result looks closer to Windows native look and feel than Swing. Especially the feel. Yet, until last week I was running my Windows XP box with the Classic theme (that is a slightly improved Windows 2000 look).

So, tonight, I decided to take a look at the infamous file chooser. I used Eclipse 3.2 M1, NetBeans 5.0 daily 20050925, Notepad.exe and Java SE 6 1.6 b53. Here are the results:


Fig. 1. Notepad.exe


Fig. 2. NetBeans 5.0 daily 20050925


Fig. 3. Eclipse 3.2 M1

Now here is my question: did I do something wrong while configuring Eclipse? I usually run with the Eclipse 2.1 appearance but I also tried with the default. I even tried to run a clean install on a new workspace, just in case. I also find weird that scrollbars have Windows XP look but not the buttons. Is this because of SWT or because of me?



Synth Week, File Chooser

Posted by gfx on September 23, 2005 at 10:59 PM | Permalink | Comments (3)

When you bring up a Swing file chooser in Tiger with the Synth look and feel you get a perfectly blank window. Styling JFileChooser requires bindings for scrollbars, tables, buttons, combo box, buttons, text fields and labels. Needless to say it's a rather difficult task. Despite your efforts you won't unfortunately be able to fully style it. It appears that Tiger provides no way to specify icons for files, directories, drives and floppies, making almost impossible for users to make the difference between a file and a folder. Ouch.

Fear not my friends, for this issue has been addressed by bug fix #4972060. You can now declare a few properties to draw the appropriate icons:

<defaultsProperty key="FileView.directoryIcon" value="directoryIcon" />
<defaultsProperty key="FileView.fileIcon" value="fileIcon" />
<defaultsProperty key="FileView.computerIcon" value="computerIcon" />
<defaultsProperty key="FileView.hardDriveIcon" value="hardDriveIcon" />
<defaultsProperty key="FileView.floppyDriveIcon" value="floppyDriveIcon" />

Note that each value is the ID of an <imageIcon /> declared in the same style element. Anyway, everything's fine, right? Well... almost.

Contrary to most file choosers, especially Basic, Metal and Windows ones, Synth file chooser is lacking four features: create a new folder, browse to parent folder, go to home directory and the choice between the list view and the detailled view. We therefore tackled bug #4972060. These features appear as three buttons and a couple of toggle buttons on top of the file chooser. You can set their icons in a similar fashion as file view icons:

<defaultsProperty key="FileChooser.newFolderIcon" value="newFolderIcon" />
<defaultsProperty key="FileChooser.upFolderIcon" value="upFolderIcon" />
<defaultsProperty key="FileChooser.homeFolderIcon" value="homeFolderIcon" />
<defaultsProperty key="FileChooser.detailsViewIcon" value="detailsViewIcon" />
<defaultsProperty key="FileChooser.listViewIcon" value="listViewIcon" />

You should now be able to give file choosers the exact appearance you were wishing for.



Synth Week, Components Orientation Support

Posted by gfx on September 23, 2005 at 12:32 AM | Permalink | Comments (7)

Many Swing components can be oriented according to your needs. Scrollbars are among the most common oriented components. Despite some support in Synth for oriented components, it is far from being exhaustive in Tiger. While some left aside components can be easily forgotten, for instance the window of a floatable toolbar being dragged, Synth lacked support for important oriented components, like scrollbars. Scrollbars are a great example because many users ran into the problem of skinning both horizontal and vertical scrollbars with a different picture. The following snippet shows how to style scrollbars' track:

<style id="scrollbarTrackStyle">
    <state>
        <imagePainter method="scrollBarTrackBackground"
        path="images/scrollBar-track.png" sourceInsets="0 7 0 7" />
    </state>
</style>
<bind style="scrollbarTrackStyle" type="REGION" key="ScrollBarTrack" /> 

This code works fine when you use a picture which can be stretched horizontally or vertically. Unfortunately, most modern look and feels require the use of gradients to show good looking scrollbars and this is where the problem arise. Take a look at the following screenshot and compare the two scrollbars:


Fig. 1. Ouch, scrollbars look... weird.

The result is not really surprising since we use only one picture for both scrollbars. This picture is a gradient meant to be stretched on the vertical axis, thus the glitch in the horizontal scrollbar. By taking a closer look at Synth documentation we discover a special attribute for painters, called "direction". On the screenshot, you can notice the four arrow buttons (two for each scrollbar) are rendered perfectly, thanks to the direction attribute:

<style id="scrollBarArrowStyle">
    <state>
        <imagePainter method="arrowButtonForeground"
         path="images/scrollBar-up.png" center="true" direction="north" />
        <imagePainter method="arrowButtonForeground"
         path="images/scrollBar-down.png" center="true" direction="south" />
        <imagePainter method="arrowButtonForeground"
         path="images/scrollBar-left.png" center="true" direction="west" />
        <imagePainter method="arrowButtonForeground"
         path="images/scrollBar-right.png" center="true" direction="east" />
    </state>
</style>
<bind style="scrollBarArrowStyle" type="REGION" key="ArrowButton" /> 

It would be logical to do the same for the track but you can't because Synth doesn't support direction for scrollbars tracks. And for many other components and methods for that matter. Filed as bug #5033822, this issue is fixed in Mustang b53. Instead of fixing scrollbars only, we took a look at all Swing components and added orientation support wherever we could. This means you can now skin oriented tabbed panes (and their sub-regions), toolbars, etc. The following snippet addresses the issue for our scrollbars:

<style id="scrollbarTrackStyle">
    <state>
        <imagePainter method="scrollBarTrackBackground"
         path="images/scrollBar-track-horizontal.png"
         direction="horizontal" sourceInsets="0 7 0 7" />
        <imagePainter method="scrollBarTrackBackground"
         path="images/scrollBar-track-vertical.png"
         direction="vertical" sourceInsets="7 0 7 0" />
    </state> 
</style>
<bind style="scrollbarTrackStyle" type="REGION" key="ScrollBarTrack" /> 

Synth can now render the scrollbars properly, as in the following screenshot:


Fig. 2. Thanks to Mustang, scrollbars (and other components) look great.

Adding extensive oriented components support in Synth required a lot of changes in SynthPainter. Therefore, some methods might have been forgotten. In such a case, just send me an email and I'll add the missing method as soon as possible.



Synth Week, Custom Lines Style

Posted by gfx on September 21, 2005 at 11:41 PM | Permalink | Comments (6)

Every Swing look and feel relies on properties to customize the rendering. One of these properties allows you, With BasicLookAndFeel and therefore Metal and Ocean, to change JTree's lines style from solid to dashed:

UIManager.put("Tree.lineTypeDashed", Boolean.TRUE);

The following screenshot shows the difference between dashed tree lines on the left and regular solid tree lines on the right.


Fig. 1. Regular and dashed lines style in a JTree.

Although not vital, this feature was used from time to time and was unfortunately unsupported by Synth. Actually, bug #6258272 reporting this problem had even 3 votes. As part of Mustang b53, this bug is now fixed but instead of just supporting dashed lines we went a step further and added an opportunity for later enhancements. The following snippets enables dashed tree lines in Synth:

<style id="treeStyle">
  <property key="Tree.linesStyle" type="string" value="dashed" />
</style>

As you can see, the property used in Synth is more generic than BasicLookAndFeel. Even though only two styles are supported, dashed and the default one which is solid, you can easily create your own. Indeed, whenever you declare a Synth style (which you later bind to a region or a component by its name), you can provide a graphics utilities entity:

<style id="myStyle">
  <object class="MyGraphicsUtils" id="graphics" />
  <graphicsUtils idref="graphics" />
</style>

The specified class, in this case MyGraphicsUtils, derives from javax.swing.plaf.synth.SynthGraphicsutils and provides several helper methods Synth invokes to render components. One of these methods is drawLine():

void drawLine(SynthContext context, Object paintKey, Graphics g,
              int x1, int y1, int x2, int y2)

The paintKey identifies the type of line. A tree will for instance draw lines of type "Tree.horizontalLine" and "Tree.verticalLine". Since this method is invoked by several UI delegates, the paintKey must be used to change the behavior according not only to the component but also to which line is being drawn. Mustang b53 adds new drawLine() method with the following signature:

void drawLine(SynthContext context, Object paintKey, Graphics g,
              int x1, int y1, int x2, int y2, Objet styleKey)

A new parameter called styleKey identifies the requested style of the line being drawn. In current implementation the only special style supported is "dashed", and only for horizontal (y1 == y2) and vertical lines (x1 == x2). Oblique lines are drawn with the default solid style. You must also know that only JTree will benefit from this new method. If it proves to be useful, we will gradually add support of styled lines to other components as well. Nevertheless, the styleKey gives you a new degree of freedom; you can for instance use it to paint curved lines in a tree as in the following example (screenshot from the chat demo of JavaOne 2005 session Extreme GUI Makeover):


Fig. 2. Curved lines style.

Happy styling!



Synth Week, Load Themes From Anywhere

Posted by gfx on September 21, 2005 at 03:10 AM | Permalink | Comments (4)

Chase Away Those Fierce Nightmares

In Tiger and early Mustang builds, Synth falls short providing a versatile, efficient and easy to use way to load a theme. Only one method is offered to load a Synth theme, the mischievous SynthLookAndFeel.load(). Albeit easy to use, this method suffers from critical limitations.

When your program invokes it, two parameters must be specified: an input stream containing the XML theme and a Class used to resolve resources path. If the theme declares using the picture “images/button_pressed.png”, the path to the PNG file will be constructed from the .class file of the specificed Class. For instance, here is how you would load a Synth theme from within the jar containing your application:

SynthLookAndFeel.load(getClass().getResourceAsStream(“synth.xml”),
                      getClass());

This snippet fits very well in most applications, those in which Synth themes are embedded. Unfortunately this method implies that you must ship a .class file with your theme, even if no Java code is required. Even worse, it is very difficult to let the users load a new theme from an arbitrary location, especially a directory or a compressed archive. I am sure many developers have been flummoxed by the uncanny experience of attempting to load a theme from a directory.


Fig. 1. A pissed developer.

Mustang beta will hopefully chase away your worst nightmares; at least if you are insane enough to dream of cunning and bad tempered Synth look and feels. Whether you don't sleep at night or you just want to know more about Synth, behold the new load() method, capable of fetching a Synth theme from an URL:

public void load(URL url) throws ParseException, IOException

Thus Freed from the Darkness, You Shall Prevail

But a greater peril lies ahead! To achieve your journey you will need to tame an ancient beast, the URL class. Silently lurking in its den, the java.net package, this class seems so old and simple that even the frailest insane elderly should be able to bend it to his will. Alas! Those ancient creatures are astute and disingenuous and they will lure you into a trap of great complexity.


Fig. 2. A developer approaching the dreaded deadline.

With the addition of this single new method you can now load Synth themes from pretty much anywhere. At one condition, you must know how to use URL in Java. Here is a short list of possible locations for your themes:

  • A local file ;
  • Files scattered on an HTTP server ;
  • A local jar file ;
  • A jar file on an HTTP server ;
  • A servlet.

Possibilities are endless and they all prove to be very interesting. You can for instance imagine a servlet dynamically generating Synth files and resources. Whenever you load a theme from a URL, Synth will find the required resources by generating paths relative to the base URL you specify. Actually, Synth doesn't do much of the work here, thanks to the mighty URL class. Most of the aforementioned examples are easy to implement. The following code snippet shows for instance how to load a theme from a local file:

SynthLookAndFeel laf = new SynthLookAndFeel();
laf.load(new URL("file:///C:/java/synth/laf/laf.xml"));
UIManager.setLookAndFeel(laf);

Loading the same look and feel from an HTTP server, or a servlet for that matter, is exactly as easy:

laf.load(new URL("http://host/laf.xml"));

I stressed the fact the URL class can be difficult to use and it was for a good reason: now try, all by yourself, to find the URL required to load a Synth theme from a jar... Even if a majority of people reading this blog might now the answer, I'm pretty sure some of you are bemused. Don't panic and read the following snippet:

laf.load(new URL("jar:file:///C:/synth-laf.jar!/laf.xml"));

The “jar:” protocol can be used to access a specific file within a jar. Thus, the first part of the URL is another URL, pointing to the jar file itself, and the second part, beginning with an exclamation mark, is a path to the requested file. In this example we tell Synth to load the file “synth.xml” in the jar “synth-laf.jar”. If you look closely at the file path, you'll notice it's an absolute path. You must not forget the leading slash or you might encounter a cryptic exception. Don't worry about the paths specified in the XML file itself as you can use relative and absolute paths.

Even tough the latest example uses a local jar file this is not the only kind of location you can reach. Remember the first part of a “jar:” location is a full URL. That means you can write this to load the theme from a jar delivered by an HTTP server:

laf.load(new URL("jar:http://host/synth-laf.jar!/laf.xml"));

This is Your New Power, Use it Wisely

The new load() method as little, if none, drawbacks at this time. They also open a whole new range of possibilities for Synth. If your application is not WebStart enabled you can distribute the look and feel across the network and change it very easily without redeploying anything.

Default protocols in Java SE should prove to be enough for most applications. Nevertheless, if you need to support an exotic protocol or if you need to create your very own (what about “db:” to load from a database or “kde:” to generate a look and feel from a KDE theme) do not forget you can plug your own protocol handlers in the JDK. I won't enter in the details here but you basically need to create a new URLStreamHandler and alter the "java.protocol.handler.pkgs" system property to prepend or append the package containing your handlers.

This new feature will be available in Mustang b53 and is brought to you by bug fix #5056424.



Synth Week, Bonus Day

Posted by gfx on September 16, 2005 at 03:15 PM | Permalink | Comments (4)

Painters Aggregation

Synth lets you define a painter for each region of a component. A painter can be used, for instance, to draw a button's border or a tabbed pane's tabs. Here is a short example:

<style id="buttonStyle">
    <state>
        <imagePainter method="buttonBackground"
                         path="images/button.png"
                         sourceInsets="5 6 7 6" />
    </state>
</style>

This style declaration draws the background region of a button with an image painter. A painter is identified by its method (or the component's region to paint) and sometimes a direction. Scrollbars are a perfect example for the direction property:

<style id="scrollBarThumbStyle">
    <state>
        <imagePainter method="scrollBarThumbBackground"
                         direction="horizontal"
                         path="images/scrollBar-thumb-horizontal.png"
                         sourceInsets="0 7 0 7" />
        <imagePainter method="scrollBarThumbBackground"
                         direction="vertical"
                         path="images/scrollBar-thumb-vertical.png"
                         sourceInsets="7 0 7 0" />
    </state>
</style>

This style defines the painters for scrollbars thumbs. The pictures are stretched to match the size of the thumb they are associated to. The following pictures represent the image used as a source by the first painter and the result once applied to the component itself:



Everything works as expected. Unfortunately there is no way, using this stretching technique, to also draw a grip on the scrollbar thumb. Yet I managed to do it in the following application:


This application takes advantage of a new Sytnh feature in Mustang, painters aggregation. I you declare several equal painters in Tiger, only the last one will be used. Two painters are equal when they have the same method and the same direction. Mustang changes this behavior by aggregating them into a single painter. The resulting painter can be seen as a stack of painters, the first one declared in the XML file being at the bottom of the stack. Thus, we can achieve our "grip" effect in the scrollbar by changing our previous style:

<style id="scrollBarThumbStyle">
    <state>
        <imagePainter method="scrollBarThumbBackground"
                         direction="horizontal"
                         path="images/scrollBar-thumb-horizontal.png"
                         sourceInsets="0 7 0 7" />
        <imagePainter method="scrollBarThumbBackground"
                         direction="vertical"
                         path="images/scrollBar-thumb-vertical.png"
                         sourceInsets="7 0 7 0" />
        <imagePainter method="scrollBarThumbBackground"
                         direction="horizontal"
                         path="images/scrollBar-thumb-horizontal-grip.png"
                         center="true" />
        <imagePainter method="scrollBarThumbBackground"
                         direction="vertical"
                         path="images/scrollBar-thumb-vertical-grip.png"
                         center="true" />
    </state>
</style>

As you can see, we just create two new painters of the same method and direction as the original ones only in this case they use the property center="true" to prevent stretching.

Scrollbars thumbs are only one example of where aggregated painters come in handy and you can think of many other examples. For instance, you can easily compose a button with a gradient and a transparent gloss to create an Aqua style. By aggregating painters instead of compositing everything in one picture gives your more flexibility in case you need to modify part of the style. And remember you can aggregate more than two painters.



JRE/JDK download size?

Posted by gfx on September 13, 2005 at 07:39 PM | Permalink | Comments (15)

Every now and then we see a new blog/thread/article about JRE/JDK download size. Well, I just downloaded .NET 2.0 beta 2 and here are the file sizes:
  • Runtime: 23 MB installer
  • SDK: 324 MB installer (!)
Amusingly you need to install the runtime to install the SDK. That is a 347 MB installer to have a command line based framework plus its documentation. And I installed all of this to try Monad beta 2, a new Windows shell.

So sure the JDK could be smaller, Mustang b48 is 50 MB large, but at least it contains the runtime environment...

P.S: The install of the .NET SDK just failed because 1 GB of free disk space doesn't seem to be enough ^^

P.P.S: I installed and tried Monad. It rocks but it has serious problems, the most important being it takes 36 MB of RAM. For a command line shell. With no color. And the startup is slow. Even Cygwin performs better. That said it rocks so much I already dropped my old cmd.exe.

Zoom Pictures with SwingLabs FX

Posted by gfx on September 03, 2005 at 01:25 AM | Permalink | Comments (13)

Zoomable Image Panel

I read many Java forums and answer to a lot of questions about Java and Swing people send me by email. During the past few years, I've often seen users asking how to create a component which would let you display an image but also zoom in and out. I decided to take advantage of the SwingLabs FX module I recently introduced to provide such a component. As FX contains nice effects, I took my chance to mix everything together.

The Demo (run it)

This new demo is very similar to the one I made to present the CheckboardPanel and DropShadowPanel components. It actually uses them for better graphical result:


When you run the application, a picture is loaded into a org.jdesktop.swingx.ZoomableImagePanel. You can use the mouse wheel to zoom in or out but you can also drag the slider on the left. Here is an example with the same image zoomed in:


The API

While the component is still a bit crude, the API is really simple to use. Here is how you can create a new zoomable image with a zoom factor of 10% and a zoom level comprised between 25% and 400%:

Image image = ImageIO.read(new File("~/yosemite1.jpg"));
ZoomableImagePanel panel = new ZoomableImagePanel(image);

Getters and setters give you access to the zoom controls: minimum and maximum zoom level, zoom factor and current zoom level. The panel provides by default a support for the mouse wheel but you might want to disable it in certain cases (for instance, if you want the mouse wheel to scroll the enclosing scroll pane instead of zooming in and out):

panel.setMouseWheelSupportEnabled(false);

Finally you can change the displayed image at anytime:

panel.setImage(newImageInstance);

Do not forget that, as a panel, this component can embed children. The demo does not use this ability but puts the zoomable panel within a drop shadow panel, which in turn sits on top of a checkboard panel thanks to the stack layout.



Synth Studio

Posted by gfx on September 01, 2005 at 02:47 AM | Permalink | Comments (14)

Synth Studio EA1

Synth Studio Early Access 1 is a package of three very simple tools I wrote to help me port existing look and feels to Synth. The downloadable archive contains everything you need to run them but I haven't included the source code yet, for I need to figure out which license to use. I might even start a new java.net project if some of you are interested into helping creating a suite of tools to easy Synth look and feels creation. But let's take a look at what Synth Studio already offers.

Visual Look and Feel Grinder

For my first experiences with Synth I tried to port existing look and feels. Doing such a thing can be really painful if you take the time to capture screenshots of every component, in each possible state. It's even harder because you usually have to extract the component from its background. In the case of non rectangular components, like Alloy or Windows XP buttons, things can get pretty nasty. Visual Look and Feel Grinder helps a lot:


In this window, you can selected the look and feel of your choice in the bottom combo box. Look and feels are seeked within the classpath used when you run the application. If you use one of the startup scripts included in the archive, you can just set the CLASSPATH environment variable so that it includes the look and feel you want to "grind". Once you've selected the look and feel of your choice, you can pick a Swing component in the left palette and see it in the central area. Next, you can use the properties sheet on the right to change properties until the component is in the appropriate state. You can finally click either of the two buttons on the lower right to export the component as a PNG file with a transparent background. The result is incredibly easy to use in any good picture editing software and it can serve as excellent basis for a brand new look and feel of your own.

Look and Feel Grinder

While useful, Visual Look and Feel Grinder is quite tedious to use when you want to extract pictures for every Swing component. Look and Feel Grinder works in a very similar fashion but solely with a command line interface. By default, it will use the default platform look and feel (Metal or Ocean on Windows and Linux, Aqua on MacOS X) but you can choose your own by specifying its class name as a parameter:

$ ./LookAndFeelGrinder com.sun.java.swing.plaf.motif.MotifLookAndFeel

The tool will then create a new directory named after the look and feel and put all the generated pictures in it.


Some components will have several pictures, one per state. For instance, a JProgressBar will generate two pictures, JProgressBar_default.png and JProgressBar_disabled.png. You can see them both here:


To achieve its work, Look and Feel Grinder relies on a resource called com/sun/swing/synth/studio/resources/beans.xml

which contains a definition of the components and their states we want to generate:

<beans>
  <bean name="JButton">
    <state type="disabled" />
    <state type="empty" />
    <state type="pressed" />
  </bean>
  <!-- ... -->
</beans>

Each couple bean/state is mapped to a method of com.sun.swing.synth.studio.components.ComponentFactory. Here are the methods available for a JButton:

public abstract JComponent createJButtonDefault(ComponentContext context);
public abstract JComponent createJButtonDisabled(ComponentContext context);
public abstract JComponent createJButtonEmpty(ComponentContext context);
public abstract JComponent createJButtonPressed(ComponentContext context);

The ComponentContext is actually unused but has a future purpose. Its goal is to encapsulate all the required states to avoir declaring one method per component and state. Each method simply creates the appropriate components and sets it up so that it can be "grinded" and provide a good result. Take a look at the creation of a progress bar:

public JComponent createJScrollBarDefault(ComponentContext context) {
  JScrollBar scrollBar = new JScrollBar(JScrollBar.HORIZONTAL);
  scrollBar.setValue(50);
  scrollBar.setPreferredSize(new Dimension(300,
    scrollBar.getPreferredSize().height));
  return scrollBar;
}

Finally, the grinder calls a renderer on each component. It is, by default, a PictureComponentRenderer which, as you can guess, creates a PNG file from the component. I also started implementing a SynthComponentRenderer to generate a skeleton of the Synth look and feel in which you'll only have to modify the insets.

In the end, both grinders are really useful when used with the third tool, Insets Worker.

Insets Worker

The most annoying part of creating a Synth look and feel (apart from understanding how Synth works :) is to define the insets of each picture used for each state of each component. It is a tedious job we can't really automate and for which picture editing tool aren't really meant for. Insets Worker is a very simple application which helps you define them by loading a picture of a component and dragging guidelines:


You can load a picture by using PNG files and the load button, but you can also drag them directly from Visual Look and Feel Grinder (initiate the drag gesture on the checkboard panel beneath the component). Just drag the four guidelines until they match what you want, read the insets at the bottom and write them down in your Synth XML file. Defining the insets often require single-pixel precision and you can hardly do that with components shown at 100% of their size. Just roll your mouse wheel to zoom in and out:


Is it really a Synth Studio? Not yet...

Even though they proved to be really useful in my work, those three tools are still very crude and should be somehow integrated together. They should also be extended so that you can visually design a Synth look and feel without ever writing XML code. Such a graphical tool could even help masking a lot of Synth subtelties and make this skinning technology much easier to use. If you are interested in contributing to such a project, say so and we'll start a new java.net project.





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