Event-Driven Applications

Assignment

Review the play An Event to Remember.

Discussion

Modern computer-based applications use a graphical user interface (GUI) to interact with the user. One benefit of a GUI is that it provides a consistent interface for the user across many applications. Thus, once the user is familiar with buttons, togglebuttons, text editors and menus, the operation of different applications becomes much easier. A second benefit is that the GUI responds to user input, called events, in a sequence defined by the user, rather than following a sequence of operations defined by a program. These applications are called event-driven.

While event-driven applications are easier to use for the user, they are often more difficult to design for the programmer. No longer can a programmer look at a program and determine the order in which operations are executed. Different sections of the code can be executed in different orders depending on the desires of the user. While event-driven applications can be written in a traditional language like BASIC or Pascal, it becomes more difficult to manage the program as it gets larger. Different events can change parts of the program at different times making the tracking of changes difficult. For example, if your application has two windows open, one which displays a folder of objects and another which creates objects to put in that folder, when an object is created, both windows must be updated to reflect the change. As the complexity of such an application increases, it becomes more difficult to track changes and keep the interface updated.

Fortunately, object-oriented programming developed in parallel with the development of GUIs. In an object-oriented system like ABC, each object has parts which represent the current state of an object. Events may bring about a change in that state. If we make sure that changes in the state of an object will be reflected in the interface, we don't have to think of the problem as a change to the whole system but rather as a change to a few objects. Furthermore, if we make sure that changes can come about only as a result of the methods of its type, we can localize the code we have to consider and/or modify. This property is called encapsulation. As a system becomes increasingly large, encapsulation becomes more important, ensuring that changes to one object won't have unexpected results on other objects.

The Event-driven Process

To describe the event-driven process, the object-oriented play above was written to highlight features of the process. Like a normal play, there are actors which have roles and responsibilities in the play. Unlike a normal play, there is no sequence of dialog from beginning to end. Rather, as events occur, objects will issue messages to other objects to perform their responsibilities and the desired operations will be accomplished.

For this play, it is assumed that there is an event queue which will hold events as they are generated by the mouse and keyboard. Mouse events include buttonPress, buttonRelease and motion. The keyboard would also generate events keyPress and keyRelease although these events won't be generated in the play. Also there is a task queue, which is used by the taskmaster to keep track of tasks which should be performed. Finally, we assume that there is a stack of methods which the system will maintain to keep track of currently executing methods for a task.

The play begins by the Main Program beginning to execute.

Main 
     Initialize.
     Run taskmaster.
An instance of Main is put on the system stack and "Main" begins to execute. The first statement in main sends "Initialize" to itself. We will assume that the interface for Golf is displayed as a result of this message as shown below.
Then Main sends "Run" to an instance of Taskmaster. This instance of taskmaster is put on the system stack and the "run" method executes.
Run

  Repeat Forever
       Call ProcessEvent for GUI.
       Execute next task.
This "Repeat Forever" loop forms the heart of the main program of most event-driven applications. Its purpose is to get an event from the event queue, create a task to handle the event and execute it. To do this, an instance of the GUI is obtained and the message "ProcessEvent" is sent to it.
ProcessEvent 

     Get next event from eventQueue and call it anEvent.
     Determine which widget was clicked on.
     If widget is a pushbutton and 
        a buttonPress is followed by a buttonRelease then
        Put task "activate anEvent" for widget on task Queue.
     else
        Put task (event_name _ " anEvent") for widget on taskQueue.

The GUI will look in the event queue for an event. If it finds one, it will take it off the event queue and inspect the x,y location of the generated event. Based on the location, the GUI can tell which widget is being clicked on. In this case we will assume that the Erase button is clicked on. In the case of a pushbutton, the GUI will track whether a buttonPress followed by a buttonRelease is generated. If so it will generate an "activate anEvent" message for the button. For other widgets like windows, a task consisting of the message (event name _ "anEvent") will be generated.

If no event is queued, the application will wait until an event is generated. Note that the mouse runs independent of the application, generating events whenever the user uses the mouse. Several events, especially motion events, can be queued. The application will handle them one at a time. Once the event is processed, a task will be created and put on the task queue. The ProcessEvent will then return.

The taskmaster will then execute the next task on the task queue. For the play, we will assume that an "activate anEvent" was generated. The erase button will be put on the system stack and the message executed.

Processing the Activate

The Erase pushbutton must first find where the code is to handle the activate. It does this by looking in its parent widget. Each widget has a parent which encloses it, except for the top-most dialogbox. Thus the parent of the pushbutton is a menu and the parent of the menu is the dialogbox. Each top-most dialogbox has a manager called boss. It is this manager which we are interested in. The pushbutton then sends an "activate anEvent" message to boss which, in this case, is an instance of type Golfman.

The Golfman instance executes which ends up calling "eraseActivate" which erases the window in turn. When theWindow finishes erasing the screen, it is taken off the system stack. Subsequently, the Golfman instance and the erase pushbutton are also removed from the system stack. Having finished executing the task, the taskMaster instance calls GUI to get the next event on the queue and the process repeats.

In the Club House

Consider a second scenario where a manual page is displayed with a button on it. While a button is visible, it is not actually a pushbutton widget but a figure. Since events can only be generated for widgets in the GUI, only the window can receive button and keyboard events. Thus the task generated by a buttonPress event will be a message of "buttonPress anEvent" to the window.

The manager of the window will be an instance of Manualman. Manualman will route the event to its associated Shape and Behavior. If we assume that the figure had an associated Click behavior, following the message trail would result in the click method being executed.

The click behavior acts like an activate event for a pushbutton widget. It must look for a buttonPress/buttonRelease pair as well as two pairs of these events to track double-clicks. It does this by timing the events. If two occur within 300 milliseconds, it is considered a double-click. Check out the code for the Click behavior to see how this is actually accomplished.

Summary

Questions