A major difference in the architecture of modern programming languages designed for point-and-click user interfaces, and traditional programming languages like A-BASIC, is in how the program maintains control. In the point-and-click world, programs are "Event Driven", meaning that external events (like mouse clicks) are able to interrupt the program, forcing it to execute a "handler" for the event, whereas in the procedural model, the program decides for itself what statement to execute next.
This may sound like a drastic and un-bridgeable difference, making it next to impossible to provide a point-and-click interface from a procedural language. But like so many other so-called new technologies in the computer world, the innovations are more in the terminology or way of looking at things than in the way they actually work. Just as you don’t need C++ or Java to implement object-oriented programming techniques, you don’t need VB or .Net to implement event-driven programming techniques.
All operating systems of interest to this discussion, including AMOS, Unix, and Windows, support event interrupts for handling keyboard, network, disk, and other events which occur on their own timetables. Typically the operating system associates a driver which each type of event. The driver services the hardware, transferring data between it and memory buffers where it can be operated on by higher software levels. All these operating systems also maintain one or more run queues to schedule work to be done in time slices.
The main thing that distinguishes event-driven programming from procedural programming is that in the former, the main body of the program is a loop that waits for event messages, calling routines to process the events of interest and passing the others on to a default event handler. In a procedural (sometimes called "linear" program) , the "main loop", if any, is typically related to waiting for the user to perform some keyboard action. However, there is nothing stopping you from implementing your own wait-for-event main loop and letting the AUI translate all the events of interest (mouse, keyboard, timer) into keyboard sequences which are reduced to exit codes by INFLD. As shown below, the two models then become very similar in appearance.
In the standard event-driven model (top diagram), the operating system translates all of the events into coded messages. The main loop waits on these events, checks to see if they are of interest and passes them on to either its own hander or the default OS handler.
In the procedural version (bottom diagram), A-Shell filters the events (using the standard event-driven model), handling the ones which don’t apply to the application itself, and translating the ones that do apply into keyboard sequences which are picked up by whatever input routine is currently running (presumably INFLD). Depending on the event and or what the user types, the characteristics of the field, etc., the input routine will eventually exit, returning an exit code to the main loop. The main loop then determines from the exitcode what the next field or procedure will be, which eventually leads to another input operation and the process starts over again.
You’ll note that neither of these flow charts makes at all clear where the "real work" of the program is done. In the top model, it is all buried within the "Process Event" routine. Typically a startup event will trigger the creation of the main window in the application, and then it will be up to the user to click on a button or something equivalent to trigger the event which starts a particular process within the program. While that particular process is running (for example, generating a report), subsequent events just queue up until the current subroutine returns back to the main loop. Similarly, in the procedural version, the same thing happens. While it is generating the report, if keystrokes will just queue up, waiting until it gets back to the next input routine. In either case, you can (and should) improve the event-responsiveness of long procedures by checking to see if there are any events waiting (but in both cases that can get tricky if the subsequent events contradict the current activity.)
The main problem with the standard event-driven model, is that since there are so many possible events, you end up with myriad little event-handling routines which are difficult to keep track of and coordinate with each other. Along the same lines, any lengthy process must be broken up into event-sized chunks because suspending the event-handler for too long makes the program appear to have gone dead.
The procedural version is actually easier to work with from the programmer standpoint, because the number of events is reduced to a manageable number, and because A-Shell itself takes care of the low-level events (like painting the window) independent of the application, the application doesn’t have to artificially break lengthy procedures down into tiny independent event-sized chunks. In a business application environment, all that is really needed in a lengthy procedure like a report is that it check for a single cancel event, which can be done within the context of the current procedure without returning to the main loop.
Another advantage of the procedural model is that it allows the program to decide for itself when it is appropriate for the user to interrupt the flow of the procedure. For example, when filling out a certain type of form, there may be no reasonable need to jump around randomly from one field to another, and allowing it (which the standard event driven model is powerless to stop) may just complicate the ability of the program to both validate the data and assist the user in the data entry process by supplying appropriate defaults based on the context. In such a program, the procedural model can simply ignore misguided mouse-clicks and go from field-to-field in a logical manner until the form is filled out or the user aborts the operation.
Still, it may far from trivial or even obvious how to convert a traditional procedural data entry model to this event-driven equivalent. To help analyze that question, here is a flow chart representing the traditional field-by-field (aka "AlphaACCOUNTING-style") data entry logic:
This flowchart is quite a long ways from either of the event-drive versions above. It does actually have logic after or between each field to decide whether to proceed to the next field or jump to the "Any Change?" prompt. In many cases, programmers have kept this model but added additional logic to process other exitcode conditions, perhaps to support moving backwards on up arrow, displaying help, etc. You can actually retain this model and still support the ability to click on any field to edit it, but it means that each of the test routines (shown above as "Abort or Change Mode?") has to be upgraded to support the ability to jump to any field. This will not be efficient from a programming standpoint.
However, it would not be that difficult to change the model above to the model below:
Essentially what we have done is converted each of the "Input Field #n" routines from the previous flowchart and turned them into individual subroutines, to be called based on the value of the Fno (field number) variable. (The box marked "Input routine for Field #Fno" would probably consist of a statement of the form "on FNO call FIELD1, FIELD2, …"etc.) The condition logic "Abort or Change Mode?" in between each field from the previous model is now centralized into a single routine which is represented here by the four shaded boxes. In practice, this routine might become quite complicated in the sense of having a lot of individual IF statements to deal with the various permutations of Exitcodes and field . But, it is all nicely contained, and if carefully parameterized, a single copy of this logic can be applied to all your data entry programs. (It really just needs to know the range of field numbers, but might also benefit from access to an array of field information allowing it to make advanced decisions based on the geometry of the field layout.)
The only other step absolutely required to complete the conversion is to arrange for all of the applicable field objects to send identifiable keyboard strings that are turned into exitcodes when they are clicked. This will be a matter of displaying any fields you want clickable support for using the AUI CONTROL cmd parameter, or using the INFLD hlpidx parameter.
The last box ("Done with fields, wait for event") could be no more than the traditional "Any Change?" prompt. But to achieve a more typical GUI style, you would probably replace the "Any Change?" prompt with two or more buttons (OK and CANCEL). Upon falling out of the last field, you could use Eventwait to put the focus on one of the two buttons and allow the user to select one via the keyboard, or to click on one of the fields to go back to edit it.
Subtopics