Tutorial: Working with Forms

Most real-world applications need more than one window. In this tutorial you will build a multi-form project with a main form and a settings dialog. You will learn how to open forms modally, pass data between them, and configure common form properties.

Step 1: Set Up the Project

  1. Create a new project called MultiFormDemo via File → New Project.
  2. The IDE creates main.prg with a starter form.
  3. We will add a second source file for the settings form in the next step.

Step 2: Design the Main Form

  1. Open main.prg in the Form Designer.
  2. Set the form title to "Multi-Form Demo" and size to 700, 500.
  3. Add a Label at the top to display the current username — set cValue to "User: (none)".
  4. Add a Button with cPrompt set to "Open Settings".

Your main form code will look like this:

#include "hbbuilder.ch"

function Main()

   local oForm, oLblUser, oBtnSettings

   DEFINE FORM oForm TITLE "Multi-Form Demo" ;
      SIZE 700, 500 FONT "Segoe UI", 10

   @ 30, 50 LABEL oLblUser VALUE "User: (none)" ;
      OF oForm SIZE 300, 24

   @ 80, 50 BUTTON oBtnSettings PROMPT "Open Settings" ;
      OF oForm SIZE 140, 36 ;
      ACTION OpenSettings( oForm, oLblUser )

   ACTIVATE FORM oForm CENTERED

return nil

Step 3: Create the Settings Form

  1. Select File → New Form to add a second form to the project. Name it settings.prg.
  2. In the Form Designer for settings.prg, set the title to "Settings" and size to 400, 300.
  3. Add a Label with cValue "Your name:" at row 30, col 30.
  4. Add a TextBox (TGet) next to the label for the user to type their name.
  5. Add a CheckBox below with cPrompt "Enable dark mode".
  6. Add two buttons: "OK" and "Cancel" at the bottom.

Step 4: Implement ShowModal and Data Passing

The key technique is to call ShowModal() on the settings form. This blocks the main form until the user closes the dialog. After the modal form closes, you read back the values the user entered.

static function OpenSettings( oMainForm, oLblUser )

   local oSettings, oGetName, oChkDark, oBtnOK, oBtnCancel
   local cName := "", lDark := .F., nResult

   DEFINE FORM oSettings TITLE "Settings" ;
      SIZE 400, 300 FONT "Segoe UI", 10 ;
      STYLE "dialog"

   @ 30, 30 LABEL oLbl VALUE "Your name:" ;
      OF oSettings SIZE 100, 24

   @ 30, 140 GET oGetName VAR cName ;
      OF oSettings SIZE 220, 24

   @ 70, 30 CHECKBOX oChkDark VAR lDark ;
      PROMPT "Enable dark mode" ;
      OF oSettings SIZE 200, 24

   @ 220, 180 BUTTON oBtnOK PROMPT "OK" ;
      OF oSettings SIZE 90, 32 ;
      ACTION ( oSettings:nModalResult := 1, oSettings:Close() )

   @ 220, 280 BUTTON oBtnCancel PROMPT "Cancel" ;
      OF oSettings SIZE 90, 32 ;
      ACTION ( oSettings:nModalResult := 0, oSettings:Close() )

   nResult := oSettings:ShowModal( oMainForm )

   if nResult == 1
      oLblUser:SetValue( "User: " + cName )
      if lDark
         oMainForm:SetDarkMode( .T. )
      else
         oMainForm:SetDarkMode( .F. )
      endif
   endif

return nil
ShowModal vs. Show

Use ShowModal( oParent ) when the user must complete the dialog before returning to the parent. Use Show() for non-blocking windows that the user can switch between freely.

Step 5: Form Properties Reference

Here are the most commonly used form properties you can set in the Object Inspector or in code:

Property Type Description
cTitle String Text shown in the form's title bar.
nWidth / nHeight Numeric Form dimensions in pixels.
lMaximize Logical Whether the maximize button is enabled.
lMinimize Logical Whether the minimize button is enabled.
lResizable Logical Whether the user can resize the form.
cStyle String "normal", "dialog", or "toolwindow".
nModalResult Numeric Return value after ShowModal(). Set before calling Close().

Step 6: Build and Test

  1. Press F9 to build and run.
  2. Click "Open Settings" on the main form — the settings dialog appears modally.
  3. Type a name, toggle the checkbox, and click OK.
  4. The main form label updates to show the name you entered.
  5. Open the dialog again and click Cancel — the main form remains unchanged.

Form Lifecycle Flow

graph TD A["Main Form
ACTIVATE FORM CENTERED"] --> B["User clicks
Open Settings"] B --> C["Settings Form
ShowModal( oMainForm )"] C --> D{"User action"} D -->|"OK"| E["nModalResult = 1
Close()"] D -->|"Cancel"| F["nModalResult = 0
Close()"] E --> G["Main form reads
cName and lDark"] F --> H["Main form ignores
dialog values"] style A fill:#58a6ff,stroke:#388bfd,color:#0d1117 style C fill:#d2a8ff,stroke:#bc8cff,color:#0d1117 style E fill:#3fb950,stroke:#2ea043,color:#0d1117 style F fill:#f0883e,stroke:#d18616,color:#0d1117
Next step

Now that you can work with multiple forms, continue to the Event Handling tutorial to learn about all the event types available in HarbourBuilder.

On This Page

Getting Started Component Palette IDE Features Tutorials Reference Platforms Step 1: Set Up the Project Step 2: Design the Main Form Step 3: Create the Settings Form Step 4: Implement ShowModal and Data Passing Step 5: Form Properties Reference Step 6: Build and Test Form Lifecycle Flow