Tutorial: Event Handling

Events are the backbone of interactive applications. Every time a user clicks a button, types a key, resizes a window, or closes a form, HarbourBuilder fires an event that your code can handle. This tutorial covers all the major event types and the different ways to respond to them.

Step 1: Understanding Events in HarbourBuilder

Every HarbourBuilder control exposes a set of event properties (e.g. OnClick, OnChange). You assign a code block or a method reference to these properties. When the event fires, HarbourBuilder executes your handler.

graph LR A["User Action
(click, key, resize)"] --> B["OS Message
WM_COMMAND etc."] B --> C["HarbourBuilder
Event Dispatcher"] C --> D["Your Handler
Code Block / Method"] style A fill:#58a6ff,stroke:#388bfd,color:#0d1117 style B fill:#d2a8ff,stroke:#bc8cff,color:#0d1117 style C fill:#3fb950,stroke:#2ea043,color:#0d1117 style D fill:#f0883e,stroke:#d18616,color:#0d1117

Step 2: Generating Event Handlers via the Object Inspector

  1. Select a control on the form (e.g. a Button).
  2. In the Object Inspector, switch to the Events tab.
  3. Double-click the event name (e.g. OnClick).
  4. The IDE automatically:
    • Creates a static function stub in your source file.
    • Assigns the code block to call that function.
    • Jumps the cursor to the new function body so you can start coding.
Double-click is the fastest way

Double-clicking an event in the Object Inspector is the recommended workflow. It generates properly named handlers (e.g. OnBtnSaveClick) and wires up the code block automatically.

Step 3: OnClick — Button and Control Clicks

The most common event. Fires when the user clicks a button, label, image, or any clickable control.

Inline code block (simple logic):

oBtn:OnClick := { || MsgInfo( "Button was clicked!" ) }

Calling a separate function (complex logic):

oBtn:OnClick := { || OnBtnSaveClick( oForm, oGet ) }

static function OnBtnSaveClick( oForm, oGet )

   local cValue := oGet:GetValue()

   if Empty( cValue )
      MsgAlert( "Please enter a value." )
      return nil
   endif

   MsgInfo( "Saved: " + cValue )
   oForm:SetTitle( "Saved!" )

return nil

Step 4: OnChange — Value Changes

Fires whenever the value of an input control changes. Useful for TextBox (TGet), ComboBox, CheckBox, and Spinner controls.

oGetSearch:OnChange := { || OnSearchChange( oGetSearch, oListBox ) }

static function OnSearchChange( oGet, oList )

   local cFilter := oGet:GetValue()

   oList:Filter( { |cItem| Upper( cFilter ) $ Upper( cItem ) } )

return nil
OnChange fires on every keystroke

For TextBox controls, OnChange fires after each character typed. If you are doing expensive operations (like database queries), consider using a TTimer to debounce the input.

Step 5: OnKeyDown — Keyboard Input

Fires when a key is pressed while the control has focus. The handler receives the key code and modifier flags as parameters.

oGet:OnKeyDown := { |nKey, nFlags| OnGetKeyDown( nKey, nFlags, oGet ) }

static function OnGetKeyDown( nKey, nFlags, oGet )

   do case
   case nKey == VK_RETURN
      MsgInfo( "Enter pressed! Value: " + oGet:GetValue() )

   case nKey == VK_ESCAPE
      oGet:SetValue( "" )

   case nKey == VK_F1
      MsgInfo( "Help: type a value and press Enter." )

   endcase

return nil

Common key constants: VK_RETURN, VK_ESCAPE, VK_TAB, VK_DELETE, VK_F1 through VK_F12, VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT.

Step 6: OnResize — Form and Control Resizing

Fires when the user resizes the form. Use this to reposition or resize controls dynamically for a responsive layout.

oForm:OnResize := { || OnFormResize( oForm, oMemo, oStatusBar ) }

static function OnFormResize( oForm, oMemo, oStatusBar )

   local nW := oForm:nWidth
   local nH := oForm:nHeight

   // Make the memo fill the form with a 10-pixel margin
   oMemo:SetSize( nW - 20, nH - 80 )

   // Keep status bar at the bottom
   oStatusBar:SetPos( nH - 30, 0 )
   oStatusBar:SetSize( nW, 30 )

return nil

Step 7: OnClose — Form Closing

Fires when the user tries to close the form (clicking the X button, pressing Alt+F4, or calling Close()). Return .F. from the handler to prevent the form from closing — useful for unsaved-changes prompts.

oForm:OnClose := { || OnFormClose( oForm ) }

static function OnFormClose( oForm )

   local nAnswer

   if lDataModified
      nAnswer := MsgYesNoCancel( "Save changes before closing?" )

      do case
      case nAnswer == 1   // Yes
         SaveData()
         return .T.

      case nAnswer == 2   // No
         return .T.

      case nAnswer == 3   // Cancel
         return .F.         // Prevent closing

      endcase
   endif

return .T.
Returning .F. prevents closing

This is a powerful pattern for data-entry forms. Always give the user a way to force-close (e.g. the Cancel option) so they are never trapped in a form they cannot exit.

Event Parameters Summary

Event Parameters Return Controls
OnClick (none) ignored Button, Label, Image, Panel
OnChange (none) ignored TGet, ComboBox, CheckBox, Spinner
OnKeyDown nKey, nFlags ignored All focusable controls
OnResize (none) ignored TForm
OnClose (none) .T. allow, .F. prevent TForm

Code Block vs. Method Handler

HarbourBuilder supports two styles for event handlers:

Code block — best for short, inline logic:

oBtn:OnClick := { || oLabel:SetValue( Time() ) }

Method handler — best for complex logic that needs its own function:

oBtn:OnClick := { || OnBtnClick( oForm ) }

static function OnBtnClick( oForm )
   // Complex logic here: database calls, validation, etc.
   ...
return nil
Rule of thumb

If the handler is more than one expression, use a separate function. It keeps your form definition clean and makes the logic easier to debug and test.

Next step

Now that you understand events, continue to the Database CRUD tutorial to build a data-driven application with SQLite.

On This Page

Getting Started Component Palette IDE Features Tutorials Reference Platforms Step 1: Understanding Events in HarbourBuilder Step 2: Generating Event Handlers via the Object Inspector Step 3: OnClick — Button and Control Clicks Step 4: OnChange — Value Changes Step 5: OnKeyDown — Keyboard Input Step 6: OnResize — Form and Control Resizing Step 7: OnClose — Form Closing Event Parameters Summary Code Block vs. Method Handler