Berichten met label swing
Swing & OSGi — please play nice!
Geplaatst door Angelo van der Sijpt in Uncategorized, java op november 18, 2009
In a recent blog by Peter Karich, he showed how to create a pluggable Swing application using OSGi. While this works fine for smaller examples, you might run into more serious issues once you application starts to grow.
Plugging Swing: it leaks?
Let’s start with an application not unlike the one from aforementioned blog; it uses a window as host, and has a pluggable menu, and a pluggable table.
You can find the code we used at the end of this entry (or, for the impatient, here).
Using this pluggable system, we could end up with several curious situations. For instance, you might have a mixed look and feel in you application.
Or worse, you might end up with a UI that (sometimes) fails to start, and spits a stacktrace your way.
It leaks, but why?
Our host, and all components have been stored in separate bundles, meaning we don’t have full control about the order in which actions are performed (more about that later). However, we do know there are orders of execution that are less than ideal; let’s force one of those.
The project contains an Ant script to make things easier. From the root of the extracted project, run
$ > ant run1This starts the framework, installing the necessary bundles, but does not start them (note that this step uses Pax Runner, and therefore needs internet access). We can now start our bundles in the order we like.
A tale of two look-and-feels
After starting the framework, wait for the “Welcome to Felix” message, and run
[java] Welcome to Felix [java] ================ [java] start 2 start 1
The situation arises because the look and feel is a static concept in Swing. The menu bundle creates its JMenu before (see Menu.java, ln 30) the host sets its look and feel (Host.java, ln 51), and keep that look and feel, even when the host bundle changes it later.
Tables, ScrollPanes and NPEs
The NullPointerException above is a different story, but it goes back to the same staticness of Swing too. To force this situation, start only bundle 4.
[java] Welcome to Felix [java] ================ [java] start 4 [java] Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException [java] at net.luminis.swingosgi.part1.scrolltable.impl.TableComponent$1.run(TableComponent.java:31) [java] at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209) [java] at java.awt.EventQueue.dispatchEvent(EventQueue.java:633) [java] at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296) [java] at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211) [java] at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201) [java] at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196) [java] at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188) [java] at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
Let’s take a look at the line where this NPE happens:
JScrollPane scrollPane = new JScrollPane(table); scrollPane.getColumnHeader().setBackground(Color.blue); m_panel.add(scrollPane);
We know that the ColumnHeader is null. This is because its JTable’s responsibility to create the header, but this is only done once the table knows it is part of an AWT hierarchy. The following lines come from the 1.5 JDK on a Mac; configureEnclosingScrollPane() creates the column header. This addNotify method comes from Component, and notifies of, exactly, the event of being added to an AWT container.
public void addNotify() { super.addNotify(); configureEnclosingScrollPane(); }
Order, order!
So, the static nature of Swing and the dynamic nature of OSGi seem to hurt each other seriously here.
One way to get the application right is by fixing the order in which Swing components can be created. By starting bundle 1 first in our application, we at least fix the look and feel. Getting the scrolling table to run correctly is an entirely different story.
Regarding order, a few possible solutions spring to mind immediately,
- Put all UI stuff in one bundle
- Use OSGi bundle start levels
Sure, all UI in a single bundle will give you the control necessary, but it also defeats the purpose. OSGi start levels can at least solve the ordering issues, but will not get you out of the NullPointerException and might have more impact than you desire.
What order?
As we have seen, absolute order does not solve our problem. How about separating creation and initialization? Still, we need to impose some order, or at least some hierarchy.

We represent each Swing component by an OSGi service, and leverage the OSGi service dependency resolution to build up our hierarchy; this way, we know the host service will be started last.
- Resolve services Once the host bundle starts, we know all components are locked and loaded; the host can now start setting up Swing’s static elements like the look and feel.
- Create components Component creation ripples downward: the host gets its direct children, adding them to its container, and in the process triggering the children to get their child components.
- Initialize components Once the component creation is done, the host instructs each component to initialize; we can now be certain that all components are part of the AWT hierarchy.
To reach this situation, we introduce a new OSGi service that wraps the component.

All components are handled by a service implementing ComponentProvider; notice how methods are required to be called on the EventDispatchThread, making sure that all components are created on the EDT, while retaining the order necessary.
public interface ComponentProvider { /** * Constant to identify ComponentProvider services. */ public static final String COMPONENT_ID_KEY = "component.id"; /** * This function should always be called from the EDT. The implementor * may assume that this function is called once and before {@link #addedToContainer()} * * @return the implementors (Swing) component which it provides. */ public JComponent getComponent(); /** * Triggered when the component is added to a container. The implementation * can validate some stuff. This function must be called on the EDT. * Implementors may assume this function is called after {@link #getComponent()}. */ public void addedToContainer(); }
The getComponent function is analogous to the create step above; the addedToContainer triggers the initialize.
Let’s try that out!
To check that this actually works OK, run
$ > ant run2from the root of the project, and start the bundles in any order you like. The UI will only show up once all required components are available; notice that the Table and the ScrollPane component can be used interchangeably.
Is it all good?
For the most part, yes. You do give up some flexibility: the UI is assembled at runtime, but it is no longer possible to (easily) plug components into a running system without special provisions. Then again, how often do you deploy new Swing-based functionality to a running application?
In the example application, we use ServiceTrackers to keep track of the components needed by the host. In a real system, you should consider using some dependency management mechanism; we have used the Apache Felix Dependency Manager in the past.
The project and the story
The project mentioned above is available as a zipped Eclipse project. You can directly import this into Eclipse, or just unzip it and run the Ant build file.
To run the examples, you will need Apache Ant. Also, since we use Pax Runner, you will need an internet connection.
The presentation we gave about this at Devoxx 09 is at SlideShare.
Drag and drop feedback
Geplaatst door Marcel Offermans in Uncategorized op juni 30, 2007
Ever since applications started to use drag and drop, I have been puzzled by the lack of feedback they provide for actually figuring out where you can drop the things you’ve picked up. Time and again, this reminds me of the first graphics adventures, like Maniac Mansion, where you spent hours hovering your cursor over images on the screen in an attempt to find these magic zones that actually did something. Adventures have since moved on to more advanced puzzles, but it’s amazing to see in ’serious’ applications, the drag and drop behaviour has not improved much.
That lead me to come up with a prototype of a drag and drop application that provides you with feedback about where you can drop your items as soon as you start dragging them. This way, you don’t need to hover your mouse over all elements to see if the mouse shape changes. Instead, using the timing framework, drop zones are animated onto the glass pane to indicate where you can drop the object.

Technically, this is done by iterating over the content of a window hierarchically. As soon as a zone is identified that is a drop zone, it is marked as such. When all zones have been discovered, they are all highlighted, in this example with a simple rectangle, but you could enhance the example to create effects similar to Apple’s Exposé.
The application was developed for Java 6 and includes source code, build files and the necessary library.
Download: swing-dropzones.jar



