life is a rum go guv’nor, and that’s the truth

Mixing AWT and Swing is No Fun!

A couple of years ago I wrote the NLVM Application using Java Swing 1.4. It incorporates the Interactive Math Applets from the NLVM Website. The challenge was that those applets were written based on framework built back in the bronze ages when Netscape on Mac 8 was used heavily in the schools. At that time I Googled around to figure out how to mix Swing and AWT. I decided to ignore the warnings because of the large code base and eventually got it to work.

This past week I began updating the NLVM Application to support switching between multiple languages. On the screen that displays applets I added a JComboBox below the applet containing a list of languages that a user can select. Everything seemed to work fine until I noticed that once I clicked on the list box the applets stopped updating. After much pain and suffering and digging through the Swing source code I figured out the problem:

When JComboBox gets focus it (via javax.swing.plaf.basic.BasicPopupMenuUI.grabContainer) calls addMouseListener, addMouseMotionListener, and addMouseWheelListener on the applet, which are implemented in java.awt.Component. This is where the problems begin. All of those methods contain an innocuous line:

newEventsOnly = true;

There is the evil. The effect of this flag being set bears fruit in java.awt.Component.dispatchEventImpl where there is a set of nested if statements that begins:

if (newEventsOnly) {
if (eventEnabled(e)) {
processEvent(e);
}
}
...

The result is that none of the old AWT events (that the applets depend on) are sent after one of those listeners is added and the flag is set. It turns out, there are more methods that set the flag as well: addComponentListener, addFocusListener, addHierarchyListener, addHierarchyBoundsListener, addKeyListener, and addInputMethodListener, but the JComboBox never calls those methods.

My simple hack was to override those addXXXListener methods in my base class to prevent the calls from reaching down into Component where the flag gets set. I did this by writing a new J14Applet base class which extends java.applet.Applet and extending my former J10Applet base class from J14Applet instead of Applet. I’m sure this may have side effects but it seems to work fine for now.

As to why JComboBox was adding those listeners in the first place? I think it is so it can handle mouse messages when it has the focus but the mouse is not over the component, so I have defeated that behavior, but I can live with it. It is not as clean a hack as I would like because I want to be able to compile the applets for running on machines that don’t have a 1.4+ JVM. It would be nice to be able to have my Swing app dynamically add those methods like you can do in Ruby, but I don’t quickly see how to do that. For now, I will just change what J10Applet extends depending on what target I’m compiling for.

Leave a Reply