I first touched on the subject of resolution-independent Swing UIs and automatic support for high-DPI monitors about six months ago. This area has been pioneered by Karsten in his Looks family of look-and-feels. The code from Looks was used as a starting point of supporting resolution independence in Substance look-and-feel, and the last two versions provided the basic support, including automatic scaling of fonts, insets and other UI elements (such as check boxes, arrow icons, scroll bars and others).

When Mikael Grev has contacted me about two weeks ago about an article that he was going to write about the support for high DPI in his layout manager (MigLayout), he has provided a long-needed push for me to resume working on this part of Substance (thanks, Mikael). So, what was missing?

Quite a lot, actually, and the past two weeks have seen numerous improvements in this area across all the core Swing components. In this part, i’m going to talk about two area, alignment and baseline.

The first support for these two areas under Substance was introduced in this blog entry that showed how text components, combos and spinners have the same height (alignment). In addition, the inner texts are aligned as well (baseline). Here is a screenshot from that entry:

As it turns out, this is not an easy thing to achieve even for a fixed font size. To understand why, you need to understand how comboboxes and spinners are implemented.

  • Text components (JTextField, JFormattedTextField, JPasswordField) are simple – they have a border, insets and the actual document that is displayed. The component bounds are computed from the document size and the insets.
  • Non-editable comboboxes are more complicated. They have border, insets, arrow button and a cell renderer that shows the selected value. The cell renderer by default is a label with insets. The component bounds are computed from the label size, label insets, the combo insets and button bounds.
  • Editable comboboxes have border, insets, arrow button and a text field (editor). The text field also has border (in most cases it would a non-painting one) and insets. The component bounds are computed from the text field document size, text field insets, the combo insets and button bounds.
  • Spinners have border, insets, up button, down button and a text field (editor). The text field also has border (in most cases it would a non-painting one) and insets. The component bounds are computed from the text field document size, text field insets, spinner insets and button bounds.

So, how do you get all these components have the same height and the same text alignment? That’s the black magic of playing with the pixel insets in each one of the UI delegates. To get a small taste of what it feels like to be a look-and-feel developer, see the this source file from the Looks package.

And now imagine taking that implementation and scaling it to arbitrary font sizes (click the image to see more font sizes):

Now that is a whole new challenge – how to compute the insets of all the inner parts of comboboxes and spinners so that they scale with the resolution settings and remain globally aligned. Not to mention that the texts need to be aligned as well – here is a screenshot of three component rows under font sizes 22, 23 and 24 pixels (click to see full-size image):

Stay tuned for the next part when i will talk about scaling other visual parts of Swing UIs. Once again, thanks to Mikael for the challenge :)

Modern borders on Swing components

September 21st, 2007

One item suggested by Romain a year ago and missing up until now in Substance was an option to add lighter inner border to different components. Here is a sample screenshot of a few controls under Windows Vista:

Vista inner borders

As you can see, pretty much all the controls have a lighter inner border. Look at the checkboxes, radio buttons, scroll bars and buttons. Note that even the highlight indication on the selected list item has a lighter inner border. This approach was adopted by Microsoft designers back in Windows Vista, and has found its way into a few Synthetica themes as well.

Finally, i got around into providing this functionality in the latest binary drops of Substance. A handful of core skins now use different kinds of inner border painters, and here are a few examples.

We’ll start with Autumn skin. Here is how it looked before:

And here is how it looks now:

As you can see, pretty much all the relevant controls have lighter inner borders, including buttons, checkboxes, radio buttons, combos, text fields, scroll bars and tabs. Here is one more “before” shot under Autumn:

And here is the same application under the latest drop:

As you can see, you get consistent borders on the selected elements in lists and trees as well. This is due to the generic internal implementation of Substance border painting, which means that you get it on a very wide range of controls (including progress bars, text components, sliders and menus as well) for a very small increase in the library size.

Let’s move on to the Business skin. Here is the “before”:

And here is “after”:

Moving on to Creme skin, here is the “before”:

And here is the “after”:

Moving on to Raven Graphite skin, here is the”before”:

And the “after”:

And the last one is Raven Graphite Glass. The “before” screenshot:

And the “after”:

For more details on how to use the new inner border painter on custom Substance skins, read the source code of the relevant core skins mentioned above (until the documentation is ready).

Introducing Strider

September 16th, 2007

The previous teaser post showed a small video with “ripple” effects – an application showing a ripple overlay with waves originating on mouse click, bouncing off component borders and decaying over time, along with the superposition effects. It gives me a great pleasure to announce the first alpha drop of the Strider project (code-named Alento), that will provide these effects to Swing applications.

It provides a custom glass pane that can be installed and configured in the following way:

private RippleGlassPane rgp;

this.rgp = new RippleGlassPane(getRootPane());
this.rgp.ignoreClicksOn(JTextComponent.class, true);
this.rgp.markAsMedium(AbstractButton.class, true);
this.rgp.markAsWall(JTextComponent.class, true);
this.rgp.setOpaque(false);
this.setGlassPane(this.rgp);

The following RippleGlassPane methods can be used in the application code:

  • ignoreClicksOn – mouse clicks on the specified components will not result in a ripple wave.
  • markAsWall – bounds of the specified components will be marked as walls, resulting in ripple waves bouncing off.
  • markAsMedium – area of the specified components will be marked as medium, resulting in ripple waves propagating slower.

The current drop is in alpha stage, lacking a few features (proper support for resizing and granularity). It’s very small (about 28KB, and unlikely to gain much more as the development continues), and can be used in any Swing application. It should be noted that it’s quite CPU intensive, since the entire wave simulation is done in software.

Once again, thanks to Paul Falstad who donated the original code under the BSD license. Stay tuned for more.

Wolfgang is writing about a new component available in the latest release of Synthetica Addons called System Monitor:

If you’re interested about details on how to fetch the system information, look at this article i’ve written a few weeks ago for java.net. While some information is available in the System and Thread classes, you can access much more using JMX MBeans, including the information on threads and memory.

Note that with JMX, you can get the information not only on the current JVM, but on any running JVM that supports JMX. For now, it looks like the System Monitor component only allows tracing information on the current JVM (but i might be wrong).