Java ScreenShot
Screenshot      

Screenshot Core Java 2: Volume I - Fundamentals

Table of Contents
 9.  User Interface Components with Swing


Model-View-Controller Design Pattern

As promised, we start this chapter with a section describing the architecture of Swing components. Before we explain just what the title of this section means, let's step back for a minute and think about the pieces that make up a user interface component such as a button, a check box, a text field, or a sophisticated tree control. Every component has three characteristics:

  • Its contents, such as the state of a button (pushed in or not), or the text in a text field;
  • Its visual appearance (color, size, and so on);
  • Its behavior (reaction to events).

Even a seemingly simple component such as a button exhibits some moderately complex interaction between these characteristics. Obviously, the visual appearance of a button depends on the look and feel. A Metal button looks different from a Windows button or a Motif button. In addition, the appearance depends on the button state: when a button is pushed in, it needs to be redrawn to look different. The state depends on the events that the button receives. When the user depresses the mouse inside the button, the button is pushed in. Of course, when you use a button in your programs, you simply consider it as a button, and you don't think too much about the inner workings and characteristics. That, after all, is the job of the programmer who implemented the button. However, those programmers that implement buttons are motivated to think a little harder about them. After all, they have to implement buttons, and all other user interface components, so that they work well no matter what look and feel is installed. To do this, the Swing designers turned to a well-known design pattern: the model-view-controller pattern. This pattern, like many other design patterns, goes back to one of the principles of object-oriented design that we mentioned way back in : don't make one object responsible for too much. Don't have a single button class do everything. Instead, have the look and feel of the component associated with one object and store the contents in another object. The model-view-controller (MVC) design pattern teaches how to accomplish this. Implement three separate classes:

  • The model, which stores the contents;
  • The view, which displays the contents;
  • The controller, which handles user input.

The pattern specifies precisely how these three objects interact. The model stores the contents and has no user interface. For a button, the content is pretty trivial—it is just a small set of flags that tells whether the button is currently pushed in or out, whether it is active or inactive, and so on. For a text field, the content is a bit more interesting. It is a string object that holds the current text. This is not the same as the view of the content—if the content is larger than the text field, the user sees only a portion of the text displayed (see Screenshot-1).

Screenshot-1. Model and view of a text field

Java graphics 09fig01.gif


The model must implement methods to change the contents and to discover what the contents are. For example, a text model has methods to add or remove characters in the current text and to return the current text as a string. Again, keep in mind that the model is completely nonvisual. It is the job of a view to draw the data that is stored in the model.

Java graphics notes_icon.gif

The term "model" is perhaps unfortunate because we often think of a model as a representation of an abstract concept. Car and airplane designers build models to simulate real cars and planes. But that analogy really leads you astray when thinking about the model-view-controller pattern. In the design pattern, the model stores the complete contents, and the view gives a (complete or incomplete) visual representation of the contents. A better analogy might be the model that poses for an artist. It is up to the artist to look at the model and create a view. Depending on the artist, that view might be a formal portrait, an impressionist painting, or a cubist drawing that shows the limbs in strange contortions.

One of the advantages of the model-view-controller pattern is that a model can have multiple views, each showing a different part or aspect of the full contents. For example, an HTML editor can offer two simultaneous views of the same contents: a WYSIWYG view and a "raw tag" view (see Screenshot-2). When the model is updated through the controller of one of the views, it tells both attached views about the change. When the views are notified, they refresh themselves automatically. Of course, for a simple user interface component such as a button, you won't have multiple views of the same model.
Screenshot-2. Two separate views of the same model

Java graphics 09fig02.gif


The controller handles the user input events such as mouse clicks and keystrokes. It then decides whether to translate these events into changes in the model or the view. For example, if the user presses a character key in a text box, the controller calls the "insert character" command of the model. The model then tells the view to update itself. The view never knows why the text changed. But if the user presses a cursor key, then the controller may tell the view to scroll. Scrolling the view has no effect on the underlying text, so the model never knows that this event happened.

Design Patterns

When solving a problem, you don't usually figure out a solution from first principles. Instead, you are likely to be guided by past experience, or you may ask other experts for advice on what has worked for them. Design patterns are a method for presenting this expertise in a structured way. In recent years, software engineers have begun to assemble catalogs of such patterns. The pioneers in this area were inspired by the architectural design patterns of the architect Christopher Alexander. In his tutorial The Timeless Way of Building (Oxford University Press 1979), Alexander gives a catalog of patterns for designing public and private living spaces. Here is a typical example:

Window Place

Everybody loves window seats, bay windows, and big windows with low sills and comfortable chairs drawn up to them . . . A room which does not have a place like this seldom allows you to feel comfortable or perfectly at ease . . .

If the room contains no window which is a "place," a person in the room will be torn between two forces:

  1. He wants to sit down and be comfortable.

  2. He is drawn toward the light.

Obviously, if the comfortable places—those places in the room where you most want to sit—are away from the windows, there is no way of overcoming this conflict . . .

Therefore: In every room where you spend any length of time during the day, make at least one window into a "window place."

Screenshot-3. A window place

Java graphics 09fig03.gif


Each pattern in Alexander's catalog, as well as those in the catalogs of software patterns, follows a particular format. The pattern first describes a context, a situation that gives rise to a design problem. Then, the problem is explained, usually as a set of conflicting forces. Finally, the solution shows a configuration that balances these forces. In the "window place" pattern, the context is a room in which you spend any length of time during the day. The conflicting forces are that you want to sit down and be comfortable and that you are drawn to the light. The solution is to make a "window place." In the model-view-controller pattern, the context is a user interface system that presents information and receives user input. There are several forces. There may be multiple visual representations of the same data that need to be updated together. The visual representation may change, for example, to accommodate various look-and-feel standards. The interaction mechanisms may change, for example, to support voice commands. The solution is to distribute responsibilities into three separate interacting components: the model, view, and controller. Of course, the model-view-controller pattern is more complex than the "window place" pattern, and it needs to teach in some detail how to make this distribution of responsibilities work. You will find a formal description of the model-view-controller pattern, as well as numerous other useful software patterns, in the seminal tutorial of the pattern movement, Design Patterns—Elements of Reusable Object-Oriented Software, by Erich Gamma et al., Oracle 1995. We also highly recommend the excellent tutorial A System of Patterns by Frank Buschmann et al., John Wiley & Sons 1996, which we find less seminal and more approachable. The model-view-controller pattern is not the only pattern used in the design of Java. For example, the AWT event handling mechanism follows the "observer" pattern. One important aspect of design patterns is that they become part of the culture. Programmers all over the world know what you mean when you talk about the model-view-controller pattern or the "observer" pattern. Thus, patterns become an efficient way of talking about design problems.

Screenshot-4 shows the interactions between model, view, and controller objects.
Screenshot-4. Interactions between model, view, and controller objects

Java graphics 09fig04.gif


As a programmer using Swing components, you generally don't need to think about the model-view-controller architecture. Each user interface has a wrapper class (such as JButton or JTextField) that stores the model and the view. When you want to inquire about the contents (for example, the text in a text field), the wrapper class asks the model and returns the answer to you. When you want to change the view (for example, move the caret position in a text field), the wrapper class forwards that request to the view. However, there are occasions where the wrapper class doesn't work hard enough on forwarding commands. Then, you have to ask it to retrieve the model and work directly with the model. (You don't have to work directly with the view—that is the job of the look-and-feel code.) Besides being "the right thing to do," the model-view-controller pattern was attractive for the Swing designers because it allowed them to implement pluggable look and feel. The model of a button or text field is independent of the look-and-feel. But of course the visual representation is completely dependent on the user interface design of a particular look and feel. The controller can vary as well. For example, in a voice-controlled device, the controller must cope with an entirely different set of events than in a standard computer with a keyboard and a mouse. By separating out the underlying model from the user interface, the Swing designers are able to reuse the code for the models and even to switch user interfaces in a running program. Of course, patterns are only intended as guidance, not as religion. Not every pattern is applicable in all situations. For example, you may find it difficult to follow the "window places" pattern (see the sidebar on design patterns) to rearrange your cubicle. Similarly, the Swing designers found that the harsh reality of pluggable look-and-feel implementation does not always allow for a neat realization of the model-view-controller pattern. Models are easy to separate, and each user interface component has a model class. But, the responsibilities of the view and controller are not always clearly separated and are distributed over a number of different classes. Of course, as a user of these classes, you won't be concerned about this. In fact, as we pointed out before, you often won't have to worry about the models either—you can just use the component wrapper classes.

A Model-View-Controller Analysis of Swing Buttons

You already learned how to use buttons in the previous chapter, without having to worry about the controller, model, or view for them. Still, buttons are about the simplest user interface elements, so they are a good place to become comfortable with the model-view-controller pattern. You will encounter similar kinds of classes and interfaces for the more sophisticated Swing components. For most components, the model class implements an interface whose name ends in Model. Thus, there is an interface called ButtonModel. Classes implementing that interface can define the state of the various kinds of buttons. Actually, buttons aren't all that complicated, and the Swing library contains a single class, called DefaultButtonModel, that implements this interface. You can get a sense of what sort of data is maintained by a button model by looking at the methods of the ButtonModel interface. Table 9-1 shows the accessor methods.

Table 9-1. The accessor methods of the ButtonModel interface

getActionCommand()

The action command string associated with this button

getMnemonic()

The keyboard mnemonic for this button

isArmed()

true if the button was pressed and the mouse is still over the button

isEnabled()

true if the button is selectable

isPressed()

true if the button was pressed but the mouse button hasn't yet been released

isRollover()

true if the mouse is over the button

isSelected()

true if the button has been toggled on (used for check boxes and radio buttons)

Each JButton object stores a button model object, which you can retrieve.
JButton button = new JButton("Blue");
ButtonModel model = button.getModel();


In practice, you won't care—the minutiae of the button state are only of interest to the view that draws it. And the important information—such as whether a button is enabled—is available from the JButton class. (The JButton then asks its model, of course, to retrieve that information.) Have another look at the ButtonModel interface to see what isn't there. The model does not store the button label or icon. There is no way to find out what's on the face of a button just by looking at its model. (Actually, as you will see in the section on radio button groups, that purity of design is the source of some grief for the programmer.) It is also worth noting that the same model (namely, DefaultButtonModel) is used for push buttons, radio buttons, check boxes, and even menu items. Of course, each of these button types has different views and controllers. When using the Metal look and feel, the JButton uses a class called BasicButtonUI for the view and a class called ButtonUIListener as controller. In general, each Swing component has an associated view object that ends in UI. But not all Swing components have dedicated controller objects. So, having given you this short introduction to what is going on under the hood in a JButton, you may be wondering: Just what is a JButton really? It is simply a wrapper class inheriting from JComponent that holds the DefaultButtonModel object, some view data (such as the button label and icons), and a DefaultButtonUI object that is responsible for the button view.


Java ScreenShot
Screenshot      
Top
 

Comments