Sunday, July 15, 2012

Java Swing UI Quirks

In the enterprise world I don't get to doing desktop development often. A year ago I took over the maintenance of BDSup2Sub, a tool to convert and tweak bitmap based subtitle streams. This program is written in Java and uses Swing for the user interface. The original author mainly developed and tested it on Windows and did not polish the UI for other platforms. These days Ubuntu Linux is my primary desktop operating system (followed by Mac OS X) so I did some polishing.

Both the JVM GTK+ Look and Feel and the Ambiance theme in Ubuntu 12.04 could use a little love. While one could argue here that the bugs should be fixed in those projects instead of introducing workarounds in the applications the process is slow or fixes will never be backported to the currently stable releases.

Major annoyances

  • unreadable menu bar
Unreadable menu bar

  • dropdown menus and popups are missing borders and dropdown-shadow
Dropdown menu without borders and shadow
Popup menu without borders and shadow

  • missing menu separator
Missing menu separator

Determining the actual Look And Feel and theme

I am going to describe workarounds for the GTK Look and Feel, and one of them is only applicable for the Ubuntu Ambiance theme. I wrote some convenience methods to determine the current Look And Feel and the theme name:

Unreadable menu bar

This one is a JVM bug exposed by the Ambiance theme in Ubuntu 12.04. According to the bug report it is fixed in Java 8, but not (and never will be) in 7 and 6.

The JVM picks up the wrong colors so we have to set them explicitly. We can create a class for the action menus and use that instead of JMenu:

Menubar with correct colors

Missing borders for dropdown menus and popups

This could be actually fixed in the theme file but remember, the application should work out-of-the-box, so let's fix it by tweaking the theme in Java. The method below changes the style for the popup menus and sets the xThickness and yThickness fields to a sensible non-zero value. We have to create a JPopupMenu instance for its style to get updated and then the original SynthStyleFactory can be restored.

You can see the result on the screenshots below. They were taken after applying the fix from the next section so besides the border they also show the dropdown shadow.
Dropdown menu with borders and dropdown shadow
Popup menu with borders and dropdown shadow

Missing dropdown shadow for dropdown menus and popups

A Swing popup can have different weight (light, medium, heavy). The heavyweight popup uses a window as backend and has dropdown shadow. Heavyweight popup is not the default so we have to force it.

The util class I created for getting/setting the popup type:

Missing menu separator

This one could also be fixed by changing the theme and doing it from Java is very similar to the solution for the missing borders. We just have to manipulate a different region and create a JPopupMenu.Separator instance for its style to get updated.

Horizontal menu separator


IntelliJ IDEA is the Java IDE I use on Ubuntu Linux and the community edition is open source. Hats off to the Jetbrains developers for finding or leading me to some of the workarounds I posted above.