It is often the case that individual GUI components can aggregate the roles of both controller and viewer within the MVC pattern, and this is the case for the simple stopwatch example presented here. In the example, the aggregate viewer and controller class is called ViewerController and the full implementation is provided in the swing examples package as SwingGuiExample.
For the controller functionality of the ViewerController component, a number of buttons are added to the GUI window for starting, stopping and resetting the stopwatch. These correspond directly to the timerStart, timerStop and timerReset methods on the model's control interface. Since the control interface methods are thread safe, it is possible to call them directly from the context of the GUI thread using a standard Swing ActionListener object as shown in Figure 9.6.
When connecting control buttons to the model control interface, an anonymous instantiation of the ActionListener class is specialised by the addition of the actionPerformed method, which simply invokes the required method on the model control interface. In this example the control interface is named appControl and is an instance of the ApplicationControl interface given in Listing 9.1.
There is also the `close' button on the window frame which corresponds to the timerQuit method on the control interface. Again, this may be called directly from the GUI thread using a standard Swing WindowAdapter object as shown in Listing 9.7.
When implementing the viewer functionality using the Swing framework, it is important to bear in mind the issues described in Section 9.2.2 with respect to delayed rendering. In Swing, the process of painting the GUI components is carried out in an independent thread which accepts asynchronous notifications of changes to the presentational data. Therefore, the presentational data must be cached on receiving update notifications from the main reactor thread.
In the example given here, the viewer component accesses the current model state using the appView instance of the view interface previously shown in Listing 9.5. This provides access to a single item of presentational data, in the form of the current stopwatch timer value. In this case the raw timer data is not cached directly, but pre-formatted within the context of the Reaction view update callback. This is illustrated by the code fragment shown in Listing 9.8.
Once the cached presentational data has been updated, the Swing framework is notified of the changes using the panel repaint request method. This causes the displayed view of the data to be repainted at an arbitrary point in the future, within the context of an arbitrary Swing framework redraw thread.
The procedure used to repaint the displayed view from within the context of the Swing framework redraw thread is a standard text rendering routine, as shown in Listing 9.9. This takes the currently cached string representation of the stopwatch time and renders it to the screen at a specific position in the displayed window.
The combination of the buttons added to the GUI window in Section 9.3.1 and the rendered version of the current stopwatch time yields the window display shown in Figure 9.1. This looks and behaves just like a conventional Swing based application, even though the underlying Reaction based model is completely independent of the GUI toolkit being used.