Event-driven programming

Event-driven programming is a programming paradigm in which the flow of program execution is determined by events - for example a user action such as a mouse click, key press, or a message from the operating system or another program. An event-driven application is designed to detect events as they occur, and then deal with them using an appropriate event-handling procedure. The idea is an extension of interrupt-driven programming of the kind found in early command-line environments such as DOS, and in embedded systems (where the application is implemented as firmware). Event-driven programs can be written in any programming language, although some languages(Visual Basic for example) are specifically designed to facilitate event-driven programming, and provide an integrated development environment (IDE) that partially automates the production of code, and provides a comprehensive selection of built-in objects and controls, each of which can respond to a range of events. Virtually all object-oriented and visual languages support event-driven programming. Visual Basic, Visual C++ and Java are examples of such languages.

A visual programming IDE such as VB.Net provides much of the code for detecting events automatically when a new application is created. The programmer can therefore concentrate on issues such as interface design, which involves adding controls such as command buttons, text boxes, and labels to standard forms (a form represents an application's workspace or window). Once the user interface is substantially complete, the programmer can add event-handling code to each control as required. Many visual programming environments will even provide code templates for event-handlers, so the programmer only needs to provide the code that defines the action the program should take when the event occurs. Each event-handler is usually bound to a specific object or control on a form. Any additional subroutines, methods, or function procedures required are usually placed in a separate code module, and can be called from other parts of the program as and when needed.


Background

Before the arrival of object-oriented programming languages, event handlers would have been implemented as subroutines within a procedural program. The flow of program execution was determined by the programmer, and controlled from within the application’s main routine. The complexity of the logic involved required the implementation of a highly structured program. All of the program’s code would be written by the programmer, including the code required to ensure that events and exceptions were handled, as well as the code required to manage the flow of program execution. In a typical modern event-driven program, there is no discernible flow of control. The main routine is an event-loop that waits for an event to occur, and then invokes the appropriate event-handling routine. Since the code for this event loop is usually provided by the event-driven development environment or framework, and largely invisible to the programmer, the programmer’s perception of the application is that of a collection of event handling routines. Programmers used to working with procedural programming languages sometimes find that the transition to an event-driven environment requires a considerable mental adjustment.

The change in emphasis from procedural to event-driven programming has been accelerated by the introduction of the Graphical User Interface (GUI) which has been widely adopted for use in operating systems and end-user applications. It really began, however, with the introduction of object-oriented (OO) programming languages and development methodologies in the late 1970s. By the 1990's, object-oriented technologies had largely supplanted the procedural programming languages and structured development methods that were popular during the 70s and 80s. One of the drivers behind the object oriented approach to programming that emerged during this era was the speed with which database technology developed and was adopted for commercial use. Information system designers increasingly saw the database itself, rather than the software that was used to access it, as the central component of a computerised information system. The software simply provided a user interface to the database, and a set of event handling procedures to deal with database queries and updates.

One of the fundamental ideas behind object-oriented programming is that of representing programmable entities as objects. An entity in this context could be literally anything with which the application is concerned. A program dealing with tracking the progress of customer orders for a manufacturing company, for example, might involve objects such as "customer", "order", and "order item". An object encompasses both the data (attributes) that can be stored about an entity, the actions (methods) that can be used to access or modify the entity’s attributes, and the events that can cause the entity's methods to be invoked. The basic structure of an object, and its relationship to the application to which it belongs, is illustrated in the diagram below.

The relationship between an object and an application

The relationship between an object and an application

Before going any further, it is worth drawing the distinction between objects and classes. A class, in very general terms, is an object template that defines the attributes, methods and events that will be implemented in any object created with it. An object is an instance of a class. An analogy would be to say that "Dog" is a class, of which "Fido" is a specific instance. "Fido" has all of the generic characteristics and behaviours of the class "Dog", and responds to the same external stimuli.

The link between object-oriented programming and event-driven programming is fairly obvious. For example, objects on a Visual Basic form (usually referred to as controls) can be categorised into classes (e.g. "Button", "TextBox" etc.), and many instances of each can appear on a single form. Each class will have attributes (usually referred to as properties) that will be common to all objects of that type (e.g. "BackgroundColour", "Width" etc.), and each class will define a list of events to which an object of that type will respond. The methods (event-handlers) to handle specific events are usually provided as templates to which the programmer simply has to add the code that carries out the required action.


How event-driven programming works

The central element of an event-driven application is a scheduler that receives a stream of events and passes each event to the relevant event-handler. The scheduler will continue to remain active until it encounters an event (e.g. "End_Program") that causes it to terminate the application. Under certain circumstances, the scheduler may encounter an event for which it cannot assign an appropriate event handler. Depending on the nature of the event, the scheduler can either ignore it or raise an exception (this is sometimes referred to as "throwing" an exception). Within an event-driven programming environment, standard events are usually identified using the ID of the object affected by the event (e.g. the name of a command button on a form), and the event ID (e.g. "left-click"). The information passed to the event-handler may include additional information, such as the x and y coordinates of the mouse pointer at the time the event occurred, or the state of the Shift key (if the event in question is a key-press).

Events are often actions performed by the user during the execution of a program, but can also be messages generated by the operating system or another application, or an interrupt generated by a peripheral device or system hardware. If the user clicks on a button with the mouse or hits the Enter key, it generates an event. If a file download completes, it generates an event. And if there is a hardware or software error, it generates an event. The events are dealt with by a central event-handler (usually called a dispatcher or scheduler) that runs continuously in the background and waits for an even to occur. When an event does occur, the scheduler must determine the type of event and call the appropriate event-handler to deal with it. The information passed to the event handler by the scheduler will vary, but will include sufficient information to allow the event-handler to take any action necessary.

Event-handlers can be seen as small blocks of procedural code that deal with a very specific occurrence. They will usually produce a visual response to inform or direct the user, and will often change the system’s state. The state of the system encompasses both the data used by the system (e.g. the value stored in a database field), and the state of the user interface itself (for example, which on-screen object currently has the focus, or the background colour of a text box). An event handler may even trigger another event too occur that will cause a second event-handler to be called (note that care should be taken when writing event handlers that invoke other event-handlers, in order to avoid the possibility of putting the application into an infinite loop). Similarly, an event-handler may cause any queued events to be discarded (for example, when the user clicks on the Quit button to terminate the program).The diagram below illustrates the relationship between events, the scheduler, and the application’s event-handlers.

A simple event-driven programming paradigm

A simple event-driven programming paradigm

The pseudo-code routine below shows how a (very simple) scheduler might work. It consists of a main loop that runs continuously until some terminating condition occurs. When an event occurs, the scheduler must determine the event type, and select an appropriate event-handler (or deal with the event, if no suitable event-handler exists).

do forever: // the main scheduler loop

    get event from input stream

    if event type == EndProgram:
        quit // break out of event loop

    else if event type == event_01:
        call event-handler for event_01 with event parameters

    else if event type == event_02:
        call event-handler for event_02 with event parameters

    .
    .
    .

    else if event type == event_nn:
        call event-handler for event_nn with event parameters

    else handle unrecognized event // ignore or raise exception

end loop


The event queue

In an event-driven system, a number of events can occur in a relatively short space of time. The scheduler, and the event-handlers at its disposal, may not be able to handle all of the events immediately they occur. The obvious solution is to place unhandled events into an event queue until such time as they can be dealt with. Events are added to the end of the queue as they arrive, and are dealt with by the scheduler once they reach the front of the queue. There may well also be a priority scheme in operation in which certain types of event take priority over others. Such events may be fast-tracked through the scheduler by moving them to the head of the queue, or there may be a separate queue for priority events. The existence of the queue guarantees that all events will be handled at some point, and in some semblance of order. The length of the queue, and the time taken to process events, will probably depend on factors such as the speed of the processor, the amount of installed RAM, and the number of other applications that are running at the same time (which will obviously be competing for the same system resources). Much of the time, however, the queue will be empty, and the scheduler will be in an idle state waiting for the next event.


GUI programming

It should not be assumed that because most popular modern software applications have a graphical user interface (GUI) that event driven programming is the right solution for every programming requirement. Some software systems have a very specific role that involves them carrying out some task to completion with little or no user intervention (a C compiler, for example). Such applications are probably better served by a procedural programming paradigm. Having said that, most mainstream commercial software relies heavily on the availability of a GUI, and most GUI software is designed to be event-driven. A visual programming language such as Visual Basic and Visual C/C++ now comes with an Integrated Development Environment (IDE) that provides an extensive array of standard controls, each with its own set of events and event-handler code templates. The task of the GUI programmer is thus twofold – to create the user interface, and to write the event-handler code (and any additional code modules that might be required). The IDE provides the scheduler and the event queue, and to a large extent takes care of the flow of program execution. The GUI programmer is thus free to concentrate on the application-specific code. They will write the code required by each control or object to allow it to respond to a specific event, but do not need to know how to create the objects themselves.