3.6 More Complex Associations
Realistic object-oriented systems involve associations among numerous objects from a variety of classes. Commercial software systems might use many tens of classes and hundreds or thousands of objects. The examples involved here do not approach that scale. However, several additional classes will be introduced that use the same techniques and illustrate how such complex and realistic systems are structured.
A more realistic version of the Frame class employing association will be devised. Association is necessary because the interface of the Frame class would become unbearably complex if all of the rich functionality of a window were captured directly and exclusively in this one interface. For example, only two shapes are currently drawable (a line and a circle). But many more shapes are commonly available, including ovals, rectangles, splines, and polygons, in addition to a variety of properties that can be defined for each shape, such as its color, line thickness, line pattern, fill pattern. Clearly, attempting to control all of these details through the Frame interface alone would create an extremely long and complex interface. Furthermore, the Frame class also needs to be extended to include a wide range of interactive elements through which the user can manipulate the user interface. These interactive elements include buttons, editable text, sliders, check boxes, scrollable lists, radio buttons, and others. Even the addition to the Frame class of one or two methods for each of these interactive elements is clearly a step toward a large, unruly interface.
The responsibilities for the graphical and interactive elements of a window will be partitioned among three associated classes:
The Frame class is simplified so that it retains only those responsibilities not assigned to the Canvas and Panel classes. The Canvas class assumes the responsibilities for all drawing functions. Mouse events with a Canvas area are now associated with the Canvas and not the Frame. The Panel class assumes all responsibilities for managing interactive elements.
The definition for the revised Frame class and the new Canvas are shown below. The Panel class will be presented next.
Notice that all of the methods related to drawing (e.g., DrawText, DrawLine) have been removed from the Frame class, as the drawing methods are to be placed in the newly defined Canvas class. The methods that remain in the Frame class are those that specifically pertain to the definition and management of the Frame itself. In this way, the Frame class presents an abstraction of a bordered area on the user's display that can, under program control, be changed in position and shape. The contents of the Frame are defined by what other classes (like the Canvas and Panel classes) add to the Frame.
Notice that the methods for drawing text and graphical shapes have been moved to the Canvas class. Also notice that a Canvas object can only be constructed by associating it with a single Frame. Thus, it is not possible to have a Canvas object that is in two different Frames, nor is it possible to create a Canvas object that is not associated with a Frame.
The association between a Canvas object and a Frame object is established by the Canvas's constructor. By contrast, other examples have shown that the association between two objects can be created by a method other than a constructor (e.g., the ConnectTo methods in the Counter and Clock classes). The constructor can be used to establish a static association (one that is created when the Canvas object is created and one which does not change during the lifetime of the Canvas object). In other cases, the associations may be more dynamic. For example, a given Message object can be displayed in different Frames at different points in time during the Message object's lifetime. Dynamic associations are more naturally expressed as non-constructor methods so that these methods can be called during the lifetime of the object to change the association.
Three additional classes defining interactive control elements are introduced. By using objects of these new classes, a more interactive user interface can be created. These three classes are:
Together, these three classes provide basic controls for the user to enter data and trigger actions to be taken by the program.
The definition of the Panel class is given below. As in the Canvas class, the constructor for a Panel object takes a Frame object as a parameter. The location and shape of the Panel in the Frame with which it is associated is also required by the constructor. The overloaded Add method allows any number of Buttons and TextBoxes to appear in the Panel.
The Button class is defined below. The Button class constructor requires that the name of the Button object be defined. This name is used in two ways. First, the name will appear on the user's display as the label on the Button's graphical representation. Thus, a Button object named "Start" will appear as a bordered rectangular box on the screen surrounding the word Start. Second, when the user "pushes" the Button (i.e., the user clicks within the bordered rectangular box corresponding to the Button) the function OnPush(char*) is called, where the name of the Button is passed as the argument. The OnPush(char*) function is a new function that is being added to the simple programming environment. Thus, it is possible for the programmer to determine which of several Buttons the user has pressed by using the argument to the OnPush function and the Button object's IsNamed method.
The TextBox class, given below, allows the user to edit and/or enter data. Each TextBox appears to the user as a bordered rectangular area in which a typing cursor will appear when the mouse cursor is moved within the TextBox area. When this cursor is visible, the user may edit, erase, or add to any text that is visible in the TextBox. The TextBox will scroll long lines of text so that only a portion of the text may be visible at any one time. The current value of the TextBox may be set or queried by the program using the TextBox's methods SetText and GetText.
The TextBox is optionally constructed with a label which will appear to the left of the TextBox on the screen. The Shape of the TextBox must be wide enough to accomodate both the label and the length of the string that the user is expected to enter.
A small system that uses all of the new classes is shown below. This system presents the user with a TextBox in which the user can enter a string and, when a button labelled Copy is pressed, the current contents of the TextBox are read by the program and written to a Canvas area. Notice that the Button and the TextBox are contained within (associated with) a Panel and that both the Panel and the Canvas are contained within (associated with) a Frame object. Also notice that the OnPush method uses the IsNamed method of the Button class to test the identity of the Button object that was pushed.
The Clock class can be extended to improve the Clock class's usability. The programmer may want to make use of several different Clocks (e.g., to time different events, to have different time intervals) and the programmer needs the flexibility of defining what actions should take place whenever a Clock causes a timer event. To allow for this flexibility, the Clock class is extended as shown below. Each Clock object is constructed with a name that may be used to uniquely identify the Clock. The Clock's interval may be given on construction or, whenever the Clock is stopped, by the SetInterval method. The Clock can be controlled by its Start and Stop methods. Finally, similar to a Button object, a Clock object has an IsNamed method that tests the name of the object against the character string passed as an argument. Notice that, as in the earlier defintion, the Clock may be connected to a Counter object. At the end of each time interval, a Clock object will either call the Next() method of a Counter object to which it is connected or, if it is not connected to a Counter object, it will call the OnTimerEvent() function as described below.
An extension of the simple programming environment allows the programmer to define what action to take when a given Clock generates a timer event. The OnTimerEvent function is redefined to take a character string argument that is the name of the Clock which generated the timer event.
Due to the changes in the Frame class, the Message class must also be slightly modified. A Message object is no longer displayed directly in a Frame; instead it is displayed in a Canvas. This small change is shown in figure below.
The use of a Clock object, an object of the modified Message class, and the modified OnTimerEvent function is shown in the example below. This program is a revised version of the Blinking Text Hello World program. In this program a Clock object is used to control the blinking of the text contained in a Message object. The Clock's interval is defined in the constructor to be 500 milliseconds. The Clock is started in the OnStart method and its timer events are responded to by the OnTimerEvent method that tests the name passed as argument against the name of the Clock object.