This post collects some tips for Java AWT/Swing features that I found less than obvious in my recent programming. I’m using Oracle OpenJDK 10 on Windows 10, but all Oracle Java Documentation links refer to Java SE 8 as that is the target version of my projects.
2021-03-31: Moved all
JComboBox tips to an enhanced and corrected follow-up post, and added some more tips on other components.
Border implementations returned by BorderFactory do not allow specifying insets in addition to the (non-empty)
Border itself, but there is a simple mechanism for this: create a CompoundBorder with a visible outer border and an empty inner border taking up the desired inset space.
File Chooser Issues
The JFileChooser class has some surprising defects: save dialogs don’t ask for confirmation before overwriting a file; the extension of the selected file is not automatically added or updated when a
FileNameExtensionFilter selection changes; and extensions specified in that filter cannot contain any dots, i.e. something like
.xml.gz is impossible.
There are no built-in options to change these behaviors. You have to write custom code to address them, either after the
JFileChooser has closed or through action listeners and/or custom subclasses.
Mouse Event Handling
To handle multiple mouse events, it’s common and convenient to derive from the general classes MouseAdapter or MouseInputAdapter. But while such classes may contain handlers for all kinds of mouse events, those handlers will not actually be called unless you also add your adapter-derived instance to your component using the corresponding specific listener. That is, you must supply it separately to
addMouseWheelListener as needed. I frequently forget the latter two and then marvel why mouse motion and mouse wheel events aren’t being handled, even though I had implemented them on my adapter-derived class.
Relative Window Locations
(J)Window class has a handy method setLocationRelativeTo that centers the window on the screen or over another component. One important point here is that the centering location is calculated immediately, based on the currently known size of the window to be centered. Therefore you should place your call to
setLocationRelativeTo after any calls to
setSize, or the window will appear at the wrong location.
Resize Event Handling
To lay out components manually in a container without a layout manager, you’ll need to handle the componentResized event on the container and reposition and/or resize your components as desired. Importantly, once you’ve done that you also need to call
repaint() on the components, or the positions and/or sizes may not be updated correctly. The “may” is important: in my experience the layout works sometimes even without
revalidate/repaint, so it’s easy to forget these calls and become puzzled over the resulting intermittent layout failures.
Some Popup Tips
The documentation for PopupFactory.getPopup is somewhat confusing. The optional
owner parameter is described as “Component mouse coordinates are relative to, may be null.” This seems to imply that when an
owner is present the
y parameters would be relative to it, but that is not the case. Their documentation correctly states that both are absolute screen coordinates, and that is the case regardless of any
Also note that the contract for the
PopupFactory class, described at the top of the page, is quite serious. You must indeed call
Popup.hide on any popup obtained from a factory before you request another popup from the same factory, or else a myriad of popup remnants will be smeared across the screen!