Thursday, July 08, 2010

Miscellaneous Java Swing stuff

I was doing some Java Swing coding over the summer, and I found that there were a few issues that took a lot of time to figure out due to insufficient documentation, so I thought I would dicuss the solutions that I eventually found here. (Note: I started writing this post in July, but I only finished writing this post at the end of October)

One thing that has bugged me about clipboard operations is how to efficiently support an Edit menu in the menu bar with cut/copy/paste menu items. If a user selects cut, how is the UI supposed to know where to cut from? Do you need to write some sort of crazy handler that tracks which UI widget last had input focus, and then if that widget supports cut operations, perform the cut there? In fact, Swing has classes to do this. If you only support cut&paste operations in text widgets, then there's a TextAction class you can use. I think if you want to support more than text widgets, you might be able to use TransferHandler.getCutAction()---though I haven't investigated this second option too deeply, but I think it automatically performs a cut operation on the last widget that supports clipboard operations through a TransferHandler interface.

Another thing that bugged me with Swing is that in the Windows Look and Feel, the JTextArea defaults to using a fixed size font. This is a little bizarre because the AWT TextArea doesn't use a fixed size font, and the JTextArea using the default look and feel doesn't use a fixed size font. I would normally just set the font of a JTextArea to something else, but I couldn't find sufficient information in Swing about how to do this properly. In order to change the font, you need to specify a font size, but what size is appropriate? You can't use a "reasonable" value like 12pt, because the user might have configured their OS to use extra large fonts. Operating systems usually provide an area where you can look up information about which default font should be used in user interfaces, but it seemed like Swing didn't provide access to such information. In the end, the best compromise I could find was to grab the font used in JTextField widgets and apply them to the JTextArea. Presumably, Swing will configure JTextField widgets to use an appropriate font based on a user's settings, so applying this information to a JTextArea will give you a reasonable default. It's not a great solution, but it will have to do until this bizarre JTextArea problem is fixed (it's been there for many, many Java versions though, so I doubt it will be fixed any time soon) or until Java comes with a default look & feel that isn't so confusing and disorienting (even I have problems using the file dialogs in the default metal l&f).

Another thing that I had a hard time finding in the Java documentation is how newlines/linebreaks are handled in a JTextArea. Do they use the platform defaults? If you save the contents of a JTextArea to a file, do you have to manually convert between CR, CR/LF, and LF in order to get things in a neutral format? This is all nicely documented, but it is stored in an unusual spot.

Finally, the last Swing issue that took me a long time to figure out was how to support a JTextArea that you can resize horizontally, but which will grow vertically as you type into it. So for the purposes of word-wrapping, it behaves like it has a fixed width, but you should still be able to change that width by resizing the window. A normal understanding of the Java UI layout model suggests that this isn't possible. The preferredSize()/size()/minimumSize()/maximumSize() model can't handle things that sometimes have a fixed width but expand downwards, but sometimes lets you change the width, resulting in a different height for the widget. In fact, if you code up a JTextArea with no scroll bars but with a layout manager that can control the width of the widget, it works fine. Apparently, Java has various hacks for supporting this sort of setup, so it just works.