Developing a GUI Application with Lazarus

The following sections briefly describe a number of common steps that are useful when developing a Graphical User Interface (GUI) application with Lazarus.

We assume that the reader has a basic understanding of using Lazarus and of programming in Object Pascal.

Also see the Lazarus Tutorial.

Contents:


Create a GUI application project

Using the menu Project > New Project ... select Application. You will see, among other things, the Lazarus Source Editor and an empty form:

Source Editor Empty Form1

A new, unsaved project is created, consisting of

It is best to first save this project, using the menu Project > Save Project As .... Put the project in its own folder (you can create a new folder in the Save As dialog), and give the unit and the project appropriate names. Lazarus will also put the new names inside the files. For example,

Set project/compiler options

Also see Changing the options in a project of Getting Started with Lazarus at TU/e.

The recommended options for GUI applications are:

Project -> Compiler Options...
Opens the Compiler Options window.
Recommended settings are:
Paths:
  • No paths need to be set
  • LCL Widget Type: default
Parsing:
  • Delphi 2 Extensions
  • Include Assertion Code
  • Delphi Compatible
  • Use Ansi Strings
Code:
  • Check: Stack, I/O, Overflow, Range
  • Generate: Normal Code
  • Optimizations: Level 0 (Levels 1 and 2 should also work fine)
Linking:
  • Debugging: Display Line Numbers in Run-time Error Backtraces, (and if you want to verify memory management: Use Heaptrc Unit)
  • Target OS specific options: (Win32) GUI application
Messages:
  • Show Errors, Warnings, Notes, Hints, general info
  • Stop after number of errors: 1

Put components on a form

GUI elements (also known as widgets), such as labels, edit boxes, and buttons, are called components in Lazarus. The window that holds these components is called a form.

You can find the available components on the Component Palette:

Lazarus Main Window

The Component Palette is tabbed. Some relevant tabs and components are:

To add a component to a form:
  1. Click on the component's icon in the Component Palette.
  2. Click on the form to place an new instance of that component.
  3. Drag the component on the form to fine tune its placement; alignment guides will be shown when the position aligns with other components.
  4. Select a component, grab a handle, and drag it to resize the component.

This is what a form looks like after adding some components:

Populated Form1

Lazarus adds component declarations to the unit's *.pas file:

unit Unit1;

...

interface

...

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    PaintBox1: TPaintBox;
    Panel1: TPanel;
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

You can change the names of components to something better in the next step.

Note that components on the form are organized in a hierarchy. E.g., the form can contain a TPanel, which in turn contains a TButton. The hierarchical relationship among components is visualized in the top panel of the Object Inspector as a tree structure:

Object Inspector

Configure component properties

Components can be configured by changing their settings, also called properties in Lazarus. Properties can be inspected and edited using the Object Inspector, under the Properties tab. The Object Inspector can be opened via the Windows menu.

Some relevant properties:

To change the same property of multiple components at once, you can first select all relevant components (use Shift-click to add a component to the selection). The Object Inspector then shows all common properties, which you can subsequently edit to change them for all selected components.

The property values of components are stored in the *.lfm file. When a GUI application is started, the run-time system will create all objects on the form and will set the inital values of their properties. After start-up, the program can change property values at run-time as well.

The *.lfm file can also be viewed and edited as text, by right-clicking on the form and selecting View Source (.lfm):

object Form1: TForm1
  Left = 489
  Height = 300
  Top = 254
  Width = 400
  Caption = 'Form1'
  ClientHeight = 300
  ClientWidth = 400
  OnCreate = FormCreate
  ParentFont = False
  LCLVersion = '0.9.26'
  object PaintBox1: TPaintBox
    Height = 300
    Width = 225
    Align = alClient
    OnPaint = PaintBox1Paint
  end
  object Panel1: TPanel
    Left = 225
    Height = 300
    Width = 175
    Align = alRight
    Caption = 'Panel1'
    ClientHeight = 300
    ClientWidth = 175
    TabOrder = 0
    object Button1: TButton
      Left = 50
      Height = 25
      Top = 24
      Width = 75
      Caption = 'Button1'
      OnClick = Button1Click
      TabOrder = 0
    end
    object Button2: TButton
      Left = 50
      Height = 25
      Top = 64
      Width = 75
      Caption = 'Button2'
      TabOrder = 1
    end
  end
end

Create event handlers

User actions and internal system actions generate events that are destined for particular components. Each component can be configured with event handlers to process events that arrive at that component.

Use the Events tab of the Object Inspector to configure the event handlers for all relevant events. There are two ways of doing so:

Select an existing event handler

Here are some events and typical names of their event handlers:

Lazarus adds event handler code in two places in the *.pas source file:

  TForm1 = class(TForm)
    ...
    procedure Button1Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

...

implementation

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
begin

end;

Add your handler code in the implementation part.

The event handler's body can refer to components on the form and other form fields (see below) without further qualifiers:

procedure TForm1.Button1Click(Sender: TObject);
begin
  TButton1.Enabled := False;
  TButton2.Enabled := True;
end;

Each type of event handler has its own specific parameters. For the the OnClick event handler of a button, the Sender parameter is the actual button that was clicked. You can access it with the expression (Sender as TButton):

Several components can share the same event handler. The Sender parameter can be used to make the response of the event handler depend on which component received the event:

procedure TForm1.ButtonClick(Sender: TObject);
begin
  (Sender as TButton).Enabled := False;
end;

Add local methods (procedures/functions) to a form unit

If you need auxiliary routines (procedures or functions), you can add them as methods to the form.

Put the routine's heading in the public section of the form's class definition:

  TForm1 = class(TForm)
    ...
  private
    { private declarations }
  public
    { public declarations }
    procedure UpdateViews;
  end;

Use Code Completion:

to add skeleton code in the implementation part of the form's unit file:
procedure TForm1.UpdateViews;
begin

end;
Put your code there. Like event handlers, such routines can access all components on the form and other form fields (see below) by their name (without further qualifiers).

Add local fields (data/variables/state) to a form unit

If you wish to store some additional information with a form, you can do so in additional fields of the form. These are declared as variables, and are best put in the private section of the form's class definition:

  TForm1 = class(TForm)
    ...
  private
    { private declarations }
    FFileNameList: TStringList; { list of file names to search }
  public
    { public declarations }
    ...
  end;

Such fields (FFileNameList in the example above) are accessible inside procedures and functions defined within the form, in particular, inside its event handlers.

Add a given unit to your project

To add a given unit to a project:
  1. Copy or move the source code file *.pas of the given unit to the project folder. If it has an associated form, then also include the *.lfm file.
  2. Open the source code file in Lazarus.
  3. Select menu Project > Add editor file to project.
  4. Add the given unit's name to the uses clause of the units where you want to use the given unit.
    N.B. Both the interface part and the implementation part can have a uses clause.

Miscellaneous

Things can usually be done in various ways ... there are trade-offs ...

Visibility: default, protected, private, public

You can put functionality in

Separate algorithmic code from GUI code. In particular, do not put algorithmic code directly inside event handlers, and preferably not even in the form's unit.

Callbacks ...


© 2008, Tom Verhoeff (TU/e, Faculteit Wiskunde en Informatica)
Feedback about this page is welcome