Difference between revisions of "LCL Tips"

From Lazarus wiki
m (DisableAlign / EnableAlign)
(code highlighting and category)
Line 7: Line 7:
 
main program file:
 
main program file:
  
<delphi>
+
<delphi>program codedgui;
program codedgui;
 
  
 
{$MODE DELPHI}{$H+}
 
{$MODE DELPHI}{$H+}
Line 22: Line 21:
 
   Application.CreateForm(TMyForm, MyForm);
 
   Application.CreateForm(TMyForm, MyForm);
 
   Application.Run;
 
   Application.Run;
end.
+
end.</delphi>
</delphi>
 
  
 
And a unit containing a form:
 
And a unit containing a form:
  
<delphi>
+
<delphi>unit mainform;
unit mainform;
 
  
 
{$MODE DELPHI}{$H+}
 
{$MODE DELPHI}{$H+}
Line 77: Line 74:
 
end;
 
end;
  
end.
+
end.</delphi>
</delphi>
 
  
 
= Create controls manually without overhead =
 
= Create controls manually without overhead =
Line 86: Line 82:
 
'''For Delphians''': Contrary to Delphi the LCL (Lazarus Component Library) allows you to set nearly all properties in any order. For example under Delphi you cannot position a control if it has no parent. The LCL allows this and this feature can be used to reduce overhead.
 
'''For Delphians''': Contrary to Delphi the LCL (Lazarus Component Library) allows you to set nearly all properties in any order. For example under Delphi you cannot position a control if it has no parent. The LCL allows this and this feature can be used to reduce overhead.
  
  with TButton.Create(Form1) do begin
+
<delphi>
    // 1. creating a button sets the default size
+
with TButton.Create(Form1) do begin
    // 2. change position. No side effects, because Parent=nil
+
  // 1. creating a button sets the default size
    SetBounds(10,10,Width,Height);
+
  // 2. change position. No side effects, because Parent=nil
    // 3. change size depending on theme. Not yet, because Parent=nil
+
  SetBounds(10,10,Width,Height);
    AutoSize:=true;
+
  // 3. change size depending on theme. Not yet, because Parent=nil
    // 4. changing size because of AutoSize=true. Not yet, because Parent=nil
+
  AutoSize:=true;
    Caption:='Ok';
+
  // 4. changing size because of AutoSize=true. Not yet, because Parent=nil
    // 5. Set Parent. Now all the above takes place, but in a single action.
+
  Caption:='Ok';
    Parent:=Form1;
+
  // 5. Set Parent. Now all the above takes place, but in a single action.
  end;
+
  Parent:=Form1;
 +
end;</delphi>
  
 
When a control has a Parent, then all properties take effect immediately. Without a Parent many properties do nothing more than store the value. And as soon as the Parent is set every property is applied. This is especially true for grand children:
 
When a control has a Parent, then all properties take effect immediately. Without a Parent many properties do nothing more than store the value. And as soon as the Parent is set every property is applied. This is especially true for grand children:
  
  GroupBox1:=TGroupBox.Create(Self);
+
<delphi>GroupBox1:=TGroupBox.Create(Self);
  with GroupBox1 do begin
+
with GroupBox1 do begin
    with TButton1.Create(Self) do begin
+
  with TButton1.Create(Self) do begin
      AutoSize:=true;
+
    AutoSize:=true;
      Caption:='Click me';
+
    Caption:='Click me';
      Parent:=GroupBox1;
+
    Parent:=GroupBox1;
    end;
 
    Parent:=Form1;
 
 
   end;
 
   end;
   Form1.Show;
+
   Parent:=Form1;
 +
end;
 +
Form1.Show;</delphi>
  
 
Autosizing starts only after every parent is set up and the form becomes visible.
 
Autosizing starts only after every parent is set up and the form becomes visible.
Line 120: Line 117:
  
 
Instead of
 
Instead of
  with Button1 do begin
+
<delphi>with Button1 do begin
    Left:=10;
+
  Left:=10;
    Top:=10;
+
  Top:=10;
    Width:=100;
+
  Width:=100;
    Height:=25;
+
  Height:=25;
  end;
+
end;</delphi>
 
Use
 
Use
  with Button1 do begin
+
<delphi>with Button1 do begin
    SetBounds(10,10,100,25);
+
  SetBounds(10,10,100,25);
  end;
+
end;</delphi>
  
 
Left, Top, Width, Height are calling SetBounds. And every change of position or size invokes recalculation of all sibling controls and maybe recursively the parent and/or the grandchild controls.
 
Left, Top, Width, Height are calling SetBounds. And every change of position or size invokes recalculation of all sibling controls and maybe recursively the parent and/or the grandchild controls.
Line 137: Line 134:
 
When positioning many controls, it is a good idea to disable the recalculation of all auto sizing, aligning, anchoring.
 
When positioning many controls, it is a good idea to disable the recalculation of all auto sizing, aligning, anchoring.
  
  DisableAlign;
+
<delphi>DisableAlign;
  try
+
try
    ListBox1.Width:=ClientWidth div 3;
+
  ListBox1.Width:=ClientWidth div 3;
    ListBox2.Width:=ClientWidth div 3;
+
  ListBox2.Width:=ClientWidth div 3;
    ListBox3.Width:=ClientWidth div 3;
+
  ListBox3.Width:=ClientWidth div 3;
  finally
+
finally
    EnableAlign;
+
  EnableAlign;
  end;
+
end;</delphi>
  
 
'''Note''': Every DisableAlign call needs an EnableAlign call. For example if you call DisableAlign two times, you must call EnableAlign twice as well.
 
'''Note''': Every DisableAlign call needs an EnableAlign call. For example if you call DisableAlign two times, you must call EnableAlign twice as well.
  
 
'''For Delphians''': This works recursively. That means DisableAlign stops aligning in all child and grandchild controls.
 
'''For Delphians''': This works recursively. That means DisableAlign stops aligning in all child and grandchild controls.
 +
 +
[[Category:LCL]]

Revision as of 07:22, 4 October 2010

Deutsch (de) English (en) français (fr) русский (ru) 中文(中国大陆)‎ (zh_CN)

Creating a GUI by code

It is possible to create the GUI (Graphical User Interface) code completely by pascal code in Lazarus. Everything accessible from the IDE is also accessible by code. The example program and unit files below (codegui.lpr and mainform.pas) give you a template you can adapt. The most important part is not forgetting to set the Parent property of the components. The creation of controls inside the form is best done in the constructor of the form:

main program file:

<delphi>program codedgui;

{$MODE DELPHI}{$H+}

uses

 Interfaces, Forms, StdCtrls,
 MainForm;

var

 MyForm: TMyForm;

begin

 Application.Initialize;
 Application.CreateForm(TMyForm, MyForm);
 Application.Run;

end.</delphi>

And a unit containing a form:

<delphi>unit mainform;

{$MODE DELPHI}{$H+}

interface

uses Forms, StdCtrls;

type

 TMyForm = class(TForm)
 public
   MyButton: TButton;
   procedure ButtonClick(ASender: TObject);
   constructor Create(AOwner: TComponent); override;
 end;

implementation

procedure TMyForm.ButtonClick(ASender:TObject); begin

 Close;

end;

constructor TMyForm.Create(AOwner: TComponent); begin

 inherited Create(AOwner);
 Position := poScreenCenter;
 Height := 400;
 Width := 400;
 VertScrollBar.Visible := False;
 HorzScrollBar.Visible := False;
 MyButton := TButton.Create(Self);
 with MyButton do
 begin
   Height := 30;
   Left := 100;
   Top := 100;
   Width := 100;
   Caption := 'Close';
   OnClick := ButtonClick;
   Parent := Self;
 end;
 // Add other component creation and property setting code here

end;

end.</delphi>

Create controls manually without overhead

Set the Parent as last

For Delphians: Contrary to Delphi the LCL (Lazarus Component Library) allows you to set nearly all properties in any order. For example under Delphi you cannot position a control if it has no parent. The LCL allows this and this feature can be used to reduce overhead.

<delphi> with TButton.Create(Form1) do begin

 // 1. creating a button sets the default size
 // 2. change position. No side effects, because Parent=nil
 SetBounds(10,10,Width,Height);
 // 3. change size depending on theme. Not yet, because Parent=nil
 AutoSize:=true;
 // 4. changing size because of AutoSize=true. Not yet, because Parent=nil
 Caption:='Ok';
 // 5. Set Parent. Now all the above takes place, but in a single action.
 Parent:=Form1;

end;</delphi>

When a control has a Parent, then all properties take effect immediately. Without a Parent many properties do nothing more than store the value. And as soon as the Parent is set every property is applied. This is especially true for grand children:

<delphi>GroupBox1:=TGroupBox.Create(Self); with GroupBox1 do begin

 with TButton1.Create(Self) do begin
   AutoSize:=true;
   Caption:='Click me';
   Parent:=GroupBox1;
 end;
 Parent:=Form1;

end; Form1.Show;</delphi>

Autosizing starts only after every parent is set up and the form becomes visible.

Avoid early Handle creation

As soon as the Handle of a TWinControl is created, every change of a property changes the visual thing (called the widget). Even if a control is not visible, when it has a Handle, changes are still expensive.

Use SetBounds instead of Left, Top, Width, Height

Instead of <delphi>with Button1 do begin

 Left:=10;
 Top:=10;
 Width:=100;
 Height:=25;

end;</delphi> Use <delphi>with Button1 do begin

 SetBounds(10,10,100,25);

end;</delphi>

Left, Top, Width, Height are calling SetBounds. And every change of position or size invokes recalculation of all sibling controls and maybe recursively the parent and/or the grandchild controls.

DisableAlign / EnableAlign

When positioning many controls, it is a good idea to disable the recalculation of all auto sizing, aligning, anchoring.

<delphi>DisableAlign; try

 ListBox1.Width:=ClientWidth div 3;
 ListBox2.Width:=ClientWidth div 3;
 ListBox3.Width:=ClientWidth div 3;

finally

 EnableAlign;

end;</delphi>

Note: Every DisableAlign call needs an EnableAlign call. For example if you call DisableAlign two times, you must call EnableAlign twice as well.

For Delphians: This works recursively. That means DisableAlign stops aligning in all child and grandchild controls.