Let’s step back for a minute and think about the pieces that make up a user interface component such as a button, a checkbox, a text field, or a sophisticated tree control. Every component has three characteristics:
- Its content, 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 among 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; 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, programmers who implement buttons and all other user interface components are motivated to think a little harder about them, so that they work well no matter what look-and-feel is in effect.
To do this, the Swing designers turned to a well-known design pattern: the model-view-controller (MVC) pattern. This design pattern tells us to provide three separate objects:
- The model, which stores the content
- The view, which displays the content
- The controller, which handles user input
The pattern specifies precisely how these three objects interact. The model stores the content and has no user interface. For a button, the content is pretty trivial—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 Figure 11.1).
The model must implement methods to change the content and to discover what the content is. 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 stored in the model.
NOTE: 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 this design pattern, the model stores the complete content, and the view gives a (complete or incomplete) visual representation of the content. A better analogy might be the model who 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 with strangely contorted limbs.
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 content. For example, an HTML editor can offer two simultaneous views of the same content: a WYSIWYG view and a “raw tag” view (see Figure 11.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.
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, 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.
Figure 11.3 shows the interactions among model, view, and controller objects.
For most Swing components, the model class implements an interface whose name ends in Model; in this case, the interface is called ButtonModet. 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 the sort of data maintained by a button model by looking at the properties of the ButtonModet interface—see Table 11.1.
Each JButton object stores a button model object which you can retrieve.
var button = new JButton(“Btue”);
ButtonModet model = button.getModet();
In practice, you won’t care—the minutiae of the button state are only of interest to the view that draws it. All the important information—such as whether a button is enabled—is available from the JButton class. (Of course, the JButton then asks its model 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 Section 11.4.2, “Radio Buttons,” on p. 654, this 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, checkboxes, 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 read 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 BasicButtonUI object that is responsible for the button view.
Source: Horstmann Cay S. (2019), Core Java. Volume I – Fundamentals, Pearson; 11th edition.