Controls and Events

The commands to create a controls must specify event handlers that are associated with user actions made on those controls (clicking, double-clicking, selecting, etc.). There are two ways to set up event handlers. A branch label may be specified as an event handler, or a subroutine may be specified as an event handler. A program may use either subroutines or branchlabels or a combination as event handers. Both ways are discussed below.

Program Flow

User events will only be serviced when your program is paused at a wait or input command, or when it encounters a scan command. It doesn't just stop in the middle of what its doing, leaving loose ends. Also, be aware that when a sub is used as an event handler, it will go back to what it was doing once the sub is finished. So if your program was paused at a wait command, it will go back to that state once an event handler has been executed. Likewise if a program serviced an event handler at a scan statement. It will return to begin execution at the statement after the scan statement once the event handler sub is completed.

Branch Label Event Handlers

  button #main.accept, "Accept", [userAccepts], UL, 10, 10

This adds a button to the window (#main) labeled "Accept". When the program is run, and the user clicks on this button, then execution branches to the event handler routine at the label [userAccepts]. When the user clicks on the button, it generates an event. This is generally how branch label arguments are used in Liberty BASIC windows and controls.

Liberty BASIC can only respond to events when execution is halted at in INPUT or WAIT statement, or when a SCAN command is issued. Here is a short program:

  'This code demonstrates how to use checkboxes in
  'Liberty BASIC programs
  nomainwin
  button #1, " &Ok ", [quit], UL, 120, 90
  checkbox #1.cb, "I am a checkbox", [set], [reset], 10, 10, 130, 20
  button #1, " Set ", [setCheckBox], UL, 10, 50, 40, 25
  button #1, " Reset ", [resetCheckBox], UL, 60, 50, 50, 25
  textbox #1.text, 10, 90, 100, 24
  WindowWidth = 190
  WindowHeight = 160
  open "Checkbox test" for dialog as #1
  print #1, "trapclose [quit]"
  'wait here for user actions
  wait

[setCheckBox]
  print #1.cb, "set"

[set]
  print #1.cb, "value? t$"
  print #1.text, "I am "; t$
  wait

[resetCheckBox]
  print #1.cb, "reset"

[reset]
  print #1.cb, "value? t$"
  print #1.text, "Checkbox is "; t$
  wait

[quit]
  close #1
  end

In the above code, Liberty BASIC opens a small window with a checkbox, a textbox, and a few buttons. After that, it stops at the WAIT statement just after the branch label [waitHere]. At this time, if the user clicks one of the buttons or the checkbox, Liberty BASIC can handle the event and go to the appropriate branch label. The code can be observed in action by stepping through it with the debugger.

Subroutine Event Handlers

  button #main.accept, "Accept", userAcceptsSub, UL, 10, 10

This adds a button to the window (#main) labeled "Accept". When the program is run, and the user clicks on this button, then execution calls the subroutine userAcceptsSub, passing the handle of the button as an argument to the subroutine.

Liberty BASIC 3 only lets you handle events using branch labels. This works well for simple programs, but it since code executed after a branch label does not know how it was called, each control must have its own branch labels for each event it can trigger. Now with LB4 you can specify a subroutine to handle events, and when an event gets triggered the subroutine is called and information about the origins of that event, such as the handle of the control that triggered the event, get passed into the subroutine.

The old way

See in this example how each listbox needs its own handler for selection.

  gosub [loadData]
  listbox #win.pets, pet$(), [selectPet], 10, 10, 140, 150
  listbox #win.vehicles, vehicle$(), [selectVehicle], 150, 10, 150, 150
  statictext #win.label, "", 10, 170, 300, 25
  open "Branch label handler" for window as #win
  #win.pets "singleclickselect [selectPet]"
  #win.vehicles "singleclickselect [selectVehicle]"
  wait

[selectPet]
  #win.pets "selection? item$"
  print #win.label, "Pet -> "; item$
  wait

[selectVehicle]
  #win.vehicles "selection? item$"
  print #win.label, "Vehicle -> "; item$
  wait

[loadData]
  for x = 0 to 2
    read a$
    pet$(x) = a$
  next x
  for x = 0 to 2
    read a$
    vehicle$(x) = a$
  next x
  return

  data "dog", "cat", "bird"
  data "car", "bike", "boat"
  end

The new way - subroutines for event handlers

In the example the code specifies the selectionMade subroutine to handle the user actions for the two listboxes in the window. When the event handler is called, it passes the window handle into the event handler.

  gosub [loadData]
  listbox #win.pets, pet$(), selectionMade, 10, 10, 140, 150
  listbox #win.vehicles, vehicle$(), selectionMade, 150, 10, 150, 150
  statictext #win.label, "", 10, 170, 300, 25
  open "Branch label handler" for window as #win
  #win.pets "singleclickselect selectionMade"
  #win.vehicles "singleclickselect selectionMade"
  wait

  sub selectionMade handle$
    #handle$ "selection? item$"
    select case
    case handle$ = "#win.pets"
      print #win.label, "Pet -> "; item$
    case handle$ = "#win.vehicles"
      print #win.label, "Vehicle -> "; item$
    end select
  end sub

[loadData]
  for x = 0 to 2
    read a$
    pet$(x) = a$
  next x
  for x = 0 to 2
    read a$
    vehicle$(x) = a$
  next x
  return

  data "dog", "cat", "bird"
  data "car", "bike", "boat"
  end