Event Driven Programming Concepts - Part 1
by Brad Moore, copyright 2002 - all rights reserved

Home

Liberty BASIC News
Safe Registry and Ini File Alternative
Deleting and Renaming Disk Files
Segments and Flushing
Flat Toolbar with Toolips
Translating 32-bit VB API Calls
Event-Driven Programming Concepts
Spotlight on the Community!
ODBC in Liberty BASIC
Hex Viewer
Listing Files Recursively
Registering Hot Keys
Preventing more than 1 instance
Multi-Coloured Text Input Boxes
Images on Buttons and Statictext
Two Demos by David Conner

A real world event -

A gray morning began to develop outside my window. The light pitter patter of rain droplets beat upon my window as it was driven by a brisk fall wind (hey, this is Oregon!). Tucked snuggly in bed, covers tight about my neck, I shivered slightly at the thought of the wet morning that waited for me. For now, though, a pleasant dream drifted through my mind as I slept. Then it happened. From somewhere out in the ether, just inches from my head a horrifying buzz permeated my morning slumber. There is was - the alarm clock ringing in the morning. It was time to reluctantly terminate my restful sleep and begin a new task - preparing for the morning.

This is the first of several articles about event driven programming. What you just read is a real world account of an event. In the little story I was asleep and then suddenly I was awakened by an alarm clock. Once awakened I began to perform another task. The alarm clock ringing was the event trigger. It was what signaled to me that I needed to stop what I was currently doing (sleeping) and begin doing something else.

Programming: Event Based versus Lineal -

For many people the concept of event driven programming is quite foreign. This is particularly true of those who are coming from lineal languages such as Quick Basic or Fortran. In these programming languages we begin the program on line one and the program progresses through each of the lines from the top to the bottom. Maybe some user intervention causes a branching of the code, but the program is always moving from top to bottom in a lineal fashion.

Events differ from basic user intervention in one significant way. They can not be predicted. I will explain this a bit latter. For now let us look at a basic lineal program. This one is written in LB3 using the mainwin as the interface.

   'Example of Basic lineal program
  [menu]
   cls
   print
   print " *******  Temperature Conversion  *******"
   print
   print "   1) Convert Fahrenheit to centigrade"
   print "   2) Convert centigrade to Fahrenheit"
   print "   3) Quit"
   Print
   Print "   Enter Selection -> ";
   input a$
   a = val(a$)
   if a = 1 goto [F2C]
   if a = 2 goto [C2F]
   if a = 3 then
     print
     print "Thanks for using the tool"
     end
   end if
   goto [menu]

  [F2C]
   print
   print "Fahrenheit to centigrade conversion"
   print
   print "Enter Fahrenheit value -> ";
   input a$
   a = val(a$)
   if a$ <> "0" and a = 0 then goto [menu]
   print
   print a$;" degrees Fahrenheit is equal to ";
   print using("###.#",str$((a - 32) * 5/9));
   print " degrees centigrade."
   print
   print "Press enter to continue...";
   input a$
   goto [menu]

  [C2F]
   print
   print "centigrade to Fahrenheit conversion"
   print
   print "Enter centigrade value -> ";
   input a$
   a = val(a$)
   if a$ <> "0" and a = 0 then goto [menu]
   print
   print a$;" degrees centigrade is equal to ";
   print using("###.#",str$(a * 9/5 + 32));
   print " degrees Fahrenheit."
   print
   print "Press enter to continue...";
   input a$
   goto [menu]

This program features a menu for the user to select a function and it branches based on the user input. One of the trademarks of this form of program is that the system (Liberty Basic in this case) is instructed to sit and wait for one and only one expected unit of user input at each location where user intervention is required. The code above has five input statements. Each of them expects certain qualified data to be entered. Data that does not fit that qualified list of entries causes an error condition. This introduces inflexibility into the program. There is no way for me to effectively exit the program if I did not chose that option from the main menu. Once the program begins asking me for a temperature value I have no choice but to enter one.

Looking into Events -

Event driven programs are significantly different in this area. Any event that is possible can be triggered at any time. Lets look at events a little closer and see why. A basic example is a window with a couple buttons. Here is the code:

 
   'Setup
   NoMainWin
   WindowWidth = 166
   WindowHeight = 142
   UpperLeftX = Int((DisplayWidth-WindowWidth)/2)
   UpperLeftY = Int((DisplayHeight-WindowHeight)/2)
   'Add buttons
   Button #main.bt1, "Button  1",[bt1],UL, 25, 20, 105, 25
   Button #main.bt2, "Button  2",[bt2],UL, 25, 55, 105, 25
   'open the window
   Open "Window" For Window As #main
   'trap the close event (hey! this is an event!)
   Print #main, "trapclose [quit]"

  [loop]
     Wait

  [quit]
     Close #main
     End

  [bt1]
     'This does nothing really
     GoTo [loop]

  [bt2]
     'This does nothing really
     GoTo [loop]

Pretty simple code. Open a window with two buttons. What we want to see is that each of them points to their own program branch where program events are handled. These are the event handlers. In the example above, when the program executes the code at these branches, the program to simply returns back to the main loop. There is a third event handler in the code. It is the branch labeled quit, which closes the program if the user clicks on the `X' in the upper right of the window.

Each of these events are primed in the code. In the case of the buttons we have specified the event handler as a branch called [bt1]. This is required to actually do something when the event is triggered. Any valid branch name can be used. This is the "address" of where the program execution will be directed when the event is actually triggered. Here is that line of code

Button #main.bt1, "Button 1",[bt1],UL, 25, 20, 105, 25

Once the event is primed we cause the program to drop into a waiting state with the Liberty Basic command WAIT. This command will suspend program execution and wait until an event is detected for which there is an event handler setup. (By the way Liberty Basic will choke if you have control that specifies an event handler and the required label is not present when the program tries to execute it.) There is a lot of windows specific stuff that happens behind the scenes in the process of detecting the event trigger (we will look a bit deeper at that in our next installment). Until then, accept on faith that an event will be triggered when the user clicks the button labeled "Button 1" with their mouse. The trigger is like the alarm clock in the introductory scene.

Liberty Basic, having detected the event then examines the internal structures it has assembled and determines that program execution should be handled by the code that follows the branch [bt1]. This is like the new actions that take place AFTER the alarm clock rings - specifically I get out of bed to face another wet, gray Oregon morning. In the case of the button example the following code is executed:

'This does nothing really
GoTo [loop]

Obviously this code does nothing. It simply returns the program back to the wait state that it came from. As we will see in a minute, event driven programs do not have the shortfalls of the lineal forms of programming. But why is a graphic oriented program by nature event driven and why is a non-graphic oriented program usually lineal?

Why is a GUI Usually Event Driven? -

It is a good question. When one understands this concept then you have made the critical transition into the world of event driven programming. The reason is simple. I have alluded to it already. To accomplish what event driven programming accomplished in the lineal programming paradigm you would have to write a user response evaluation routine to test each and every response the user could supplied to any given input statement. This is necessary to insure that the user did not want to do something other than what the programmer expected the user to do at a given point in the code.

For instance if the user is expected to input a value for Centigrade, but instead types "Quit" then you would have to know how to handle "Quit" for that input statement (not to mention the other input statements too). What if the user typed "EXIT" instead? The possibilities are numerous - so the programmer sticks to the required input, validates it and rejects all others. This is typical in linear programming.

In the event driven world the programmer is not required to interpret the user input because the environment has defined what that input will be. Buttons for actions, fields for data and traps for menus and window functions. Each of these has definable parameters and each is handled behind the scenes with a single MACRO event handler which is embedded in the WAIT, INPUT and SCAN commands. Events simply trigger pre-built event handlers. We discussed them. It all happens as a result of the environment. It is defined by the Graphical User Interface specifications and the syntax for each command and control. As we saw in the button command - there is a place to tell the environment where to go to do the thing that needs done. It does not get any easier than that!

GUI Based Temperature Conversion Program -

To see these concepts in a little more action let's take a look at a GUI (graphical User Interface) version of our temperature conversion program.

   '** Temperature Conversion
   '   Should work in LB2 and LB3
   '   by Brad Moore
   '   released to the public domain Oct 2002

   'Window Setup
   NoMainWin
   WindowWidth = 276
   WindowHeight = 187
   'Center the window
   UpperLeftX = Int((DisplayWidth-WindowWidth)/2)
   UpperLeftY = Int((DisplayHeight-WindowHeight)/2)

   'Control Setup
   Statictext  #main.st1, "Fahrenheit", 25, 20, 75, 16
   Statictext  #main.st2, "Centigrade", 25, 45, 75, 20
   Button      #main.F2C, "Fahrenheit -> Centigrade", _
                          [F2C],UL, 20, 75, 230, 25
   Button      #main.C2F, "Centigrade -> Fahrenheit ", _
                          [C2F],UL, 20, 105, 230, 25
   Textbox     #main.tb1, 110, 15, 137, 24
   Textbox     #main.tb2, 110, 40, 137, 24

   'Open the window
   Open "Temperature Conversion" For Window As #main

   'Trap the close window EVENT (hey! this is an event trap!)
   Print #main, "trapclose [quit]"
   Print #main, "font ms_sans_serif 10"

   'Wait here for events
  [loop]
     Wait

   'Handle the close window event
  [quit]
     Close #main
     End

   'Handle the F to C event
  [F2C]
      'get contents of textbox1
      Print #main.tb1, "!contents? a$"
      'Get the numeric value and insure it is a number
      a = Val(a$)
      If a$ <> "0" and a = 0 Then
         Notice "A numeric value is required for Fahrenheit"
         GoTo [loop]
      End If
      'Display the conversion in the Other textbox
      Print #main.tb2, Using("####.#",Str$((a - 32) * 5/9))
      Wait

   'Handle the C to F event
  [C2F]
      'get contents of textbox2
      Print #main.tb2, "!contents? a$"
      'Get the numeric value and insure it is a number
      a = Val(a$)
      If a$ <> "0" and a = 0 Then
         Notice "A numeric value is required for Centigrade"
         GoTo [loop]
      End If
      'Display the conversion in the Other textbox
      Print #main.tb1, Using("####.#",Str$(a * 9/5 + 32))
      Wait

If you remember our lineal program example of the Temperature Conversion program - once you committed to converting Centigrade to Fahrenheit you were required to follow the process through. There was no way of changing your mind and converting the other way around. In the event drive environment we simply enter our data into a textbox and then press a button. The event for the button is triggered and the answer is displayed. We could have just as easily typed the value into the field and then pressed the "X" in the upper right corner of the window and triggered the [quit] event handler.

Events and Liberty Basic -

Liberty Basic allows events to be set up on many GUI based commands. In particular these that follow allow (require) events to be specified by defining a branch label to handle the event:

* Button
* Checkbox
* Combobox
* Graphicbox
* Listbox
* Menu
* Popupmenu
* Radiobutton

Events are trapped and triggered from your code where you have placed one of the following event detection commands:

* Scan
* Input
* Wait

So far we have used the Wait command, in the code above. As I described earlier this command simply waits for an event then routes the program executing to a predetermined branch label to handle the event. The Input command could have been used as well in the same case. I prefer to use the Wait command because it adds clarity to the code as it implies that the program is waiting for a user triggered event.

The Scan command is a bit more complex. The Liberty Basic help file says that the Scan command is simply an input command that does not wait. We will be covering this command in a future installment of this article series, pealing away all the mystery so that it is not so confusing.

We will also be covering event traps and timers in future installments of this article series, so please stay tuned. For now, if there are questions arising from this discussion, please post them on the Liberty Basic discussion group, or email them direct to me. Thanks.

(Also find attached to the newsletter a zip file called events-1.zip which contains this newsletter article that is formatted in pretty type, as well as both versions of the temperature calculator programs.)


Home

Liberty BASIC News
Safe Registry and Ini File Alternative
Deleting and Renaming Disk Files
Segments and Flushing
Flat Toolbar with Toolips
Translating 32-bit VB API Calls
Event-Driven Programming Concepts
Spotlight on the Community!
ODBC in Liberty BASIC
Hex Viewer
Listing Files Recursively
Registering Hot Keys
Preventing more than 1 instance
Multi-Coloured Text Input Boxes
Images on Buttons and Statictext
Two Demos by David Conner