Newsletter sign-up

Sign up for our technology specific newsletters.

Enterprise Java
View all newsletters

Email Address:

User interfaces for object-oriented systems, Part 3

The incredible transmogrifying widget

This month's Java Toolbox continues the object-oriented design/GUI theme by looking at a Collection wrapper that makes it easy to present a visual proxy, as I described in the September Java Toolbox. The wrapper, called a Bag, works just like a Collection -- it implements the java.util.Collection interface. It can, however, create a visual proxy for itself when asked.

TEXTBOX: TEXTBOX_HEAD: Build user interfaces for object-oriented systems: Read the whole series!

:END_TEXTBOX

The associated proxy can display the list of elements as a list; a button that, when pressed, pops up a frame containing the list; or a combo box. The display strategy is automatic, controlled by the size of the proxy. The list is used if there's enough space, the button is used when space is tight, and the combo box is used in an in-between situation. Moreover, several such proxies can simultaneously display the same underlying Collection (presumably, on different screens). When the Collection is changed at the model level -- by someone adding or removing a member, for example -- all the proxies will redraw themselves to reflect the change. The notion of selection is supported: When a user selects an element from the UI, a model-level object that's registered as a listener will receive notification. If several proxies are displayed, they can stay in synch with each other. If you select from one, the selections in the others will change as well. (This behavior isn't required, however.)

You may want to download the code from my Web site (see Resources) and play with this thing a bit to see how it works. Figure 1 illustrates three visual proxies simultaneously displaying the same underlying Collection. The proxy on the left is large enough to have represented itself as a list. The one at the top is a bit smaller, so it has represented itself as a combo box, while the one in the bottom right is smaller still, so it has represented itself as button, which when pressed pops up the frame window that's shown. (The button is disabled as long as the frame window is visible; it's re-enabled automatically when you close the frame.) If you resize any of these windows, they'll transmogrify into one or the other of these three forms as they get larger or smaller. Moreover, if you select a line in any of them, the other two will change to reflect that selection.

Figure 1. The Bag's visual proxy in action



This sort of dynamic adaptability is essential when implementing user interfaces using the architecture that I described in the July and September columns (which you should read before proceeding -- I assume that you're familiar with the architecture I presented in those articles). In this architecture, a control layer builds a presentation from visual proxies of attributes that are provided by an abstraction-layer object. The abstraction layer cannot know the context in which the proxy will be asked to display itself, so the proxy must accommodate whatever space is available automatically.

If the proxy wasn't adaptive in this way, the coupling between the abstraction and presentation layers would be too tight. In an HR application, for example, an employee's identity attribute might want to display a name, an employee ID, and a photograph. Moreover, it will indeed display all three items when there's enough space. If space is tight, the proxy might display itself as a button with the employee's name as the label. If pressed, the button will throw up a frame with the additional information. Adaptability is the key. In any event, all well-written Java applications should make no assumptions about the display environment. The same application that's runs on the 20-inch monitor on your desktop might also have to run on a Palm Pilot at some juncture.

Unfortunately, most of Java's built-in widgets don't work in an adaptable way out of the box. We all wish that the font size on a button's label would grow as the button grows (if it's placed in a GridBag or Grid, for example), but that's not how it works. Instead, you usually end up with minuscule text in on a huge gray button or a button that's too small for the label to print in its entirety. On the other hand, since most Swing widgets support the notion of a renderer -- an object whose job is to draw all or part of the widget -- it's relatively easy to build a set of adaptive widgets on top of Swing. That's what I've done here.

Letting the proxy out of the Bag

Before looking at the implementation, let's look at how it's used. Listing 1 shows the test class from the Bag implementation. Notice that a Bag is as easy to use as a Collection. Indeed, it's just a Collection that can produce its own UI when asked.

The main() method (Listing 1, line 26) creates a Collection by wrapping a LinkedList in a Bag, then adds a few elements to the underlying Collection through the Bag. Note that the Bag is a Collection in a real sense, so you can treat it exactly like one without difficulty (or accessed through a Collection reference). The Bag contains the actual data structure, however. (It's passed in as a constructor argument.)

The Bag is an example of the Gang-of-Four Decorator pattern (see Resources). A Decorator adds capabilities to the decorated item without using implementation inheritance (extends). The java.io package includes many examples of the Decorator pattern. The BufferedInputStream, for example, decorates another InputStream by adding buffering. You don't know whether you're dealing with an actual InputStream or a decorated one when you call read(), however. The BufferedInputStream, therefore, adds the ability to buffer input to a raw InputStream. Similarly, a Bag decorates a Collection in order to add the ability to create a visual proxy on demand.

Resources
  • A usual, the code to this month's article is available in the "Articles" section of my Web site. An index of all my previous JavaWorld articles (including the first two parts of the current series) can be found there as well. http://www.holub.com
  • Design PatternsElements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides -- the "Gang of Four" (Addison Wesley, 1994) http://www1.fatbrain.com/asp/bookinfo/bookinfo.asp?theisbn=0201633612