JFrame.add() contentPane Pain: The Complete Story
It's my fault. The fact that adding a component to a JFrame required
one to explicitly add it to the JFrame's "contentPane" is my fault.
Early on in Swing's evolution we added a runtime exception that warned
developers not to write JFrame.add(myComponent) and it has been
raising hackles ever since. Graham Hamilton covered my transgression
My Favorite (Dead) Java Boilerplate
blog and I thought I'd explain the rationale behind it's birth
and eventual demise.
It turns out that I did not create this trip-wire to incite violence
or to "educate developers about the choices" within the JFrame container.
JFrame's automatically created rootPane,
layeredPane, and contentPane substructure was designed to enable popup
effects that appear on top of the main GUI. The original motivation
for JFrame's substructure was we to support lightweight menus and
tooltips and even dialogs that appeared within a top level window.
It's also possible to use the substructure to produce novel GUI
like translucent full-window progress monitors. So why did
JFrame.add() generate an exceptional slap in the face for the
developer who's not schooled in all of this?
The 1.0 and 1.1 releases of Swing were delivered on the original Java
1.x platform. Our audience was AWT developers who typically wrote
small apps by subclassing java.awt.Frame and overriding paint() or
setting its layout manager and adding children. When we decided to
create JFrame's substructure there was a debate about the wisdom of
automatically mapping JFrame.add() to JFrame.getContentPane().add().
The reason I rejected that approach is that this "convenience" is a
shallow illusion. To complete the illusion one would have to redirect
get/setLayout(), and addComponentListener(), and getComponent() and
getChildren() and so on. In addition to making it tough to actually
get inside the JFrame itself, the complete illusion would be
asymmetrical since the source of events or a layout manager's container
wouldn't match what a developer would expect. So in the interest of
consistency, not education, we did not automatically redirect
JFrame.add() to the content pane.
Time has passed and the number of AWT developers who's expectations
might have been violated by making JFrame.add() convenient has become
pretty small. It's also true that the merits of providing a simple
trouble-free out of the box experience, even if it depends on an
imperfect illusion, are increasingly important. So, in Tiger,
JFrame's add and setLayout (and addLayout) methods have changed to "do
what you [probably] mean". The other JFrame methods, like getComponent(),
do not redirect, so if you use them, be careful. And if you don't use them,
well, ignorance is bliss.
Now that we've got that out of the way, anyone have a nomination for
a new Swing boilerplate hall of shame candidate? As far as I know,
the rest of the API is perfect.