Difference between revisions of "LCL Tips"
Sekelsenmat (talk | contribs) |
Sekelsenmat (talk | contribs) |
||
Line 168: | Line 168: | ||
</delphi> | </delphi> | ||
− | An equivalent code is: | + | An equivalent code, available in Lazarus 0.9.31+, is: |
<delphi> | <delphi> | ||
Line 176: | Line 176: | ||
begin | begin | ||
MyRegion := TRegion.Create; | MyRegion := TRegion.Create; | ||
− | MyRegion. | + | try |
− | + | MyRegion.AddRectangle(0, 0, 100, 100); | |
− | MyRegion.Free; | + | Self.SetShape(MyRegion); |
+ | finally | ||
+ | MyRegion.Free; | ||
+ | end; | ||
end; | end; | ||
</delphi> | </delphi> |
Revision as of 09:22, 18 July 2011
│
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); //Hint: FormCreate() is called BEFORE Create() ! //so You can also put this code into FormCreate() //(This is not the case when creating components ..)
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.
Creating a non-rectangular window or control
One can easily create non-rectangular windows or controls in Lazarus. For this, one can simply call TWinControl.SetShape, with the visible region as a parameter. Note that this will work for both windows and controls, as both TCustomForm and TCustomControl descend from TWinControl. One can also call the lclintf routine SetWindowRgn, which is completely equivalent to calling the SetShape method.
Using SetWindowRgn the code will be similar to this:
<delphi> uses lclintf, lcltype;
procedure TForm1.FormCreate(Sender: TObject); var
MyRegion: TRegion;
begin
MyRegion := CreateRectRgn(0, 0, 100, 100); SetWindowRgn(Handle, MyRegion, True); DeleteObject(MyRegion);
end; </delphi>
An equivalent code, available in Lazarus 0.9.31+, is:
<delphi> procedure TForm1.FormCreate(Sender: TObject); var
MyRegion: TRegion;
begin
MyRegion := TRegion.Create; try MyRegion.AddRectangle(0, 0, 100, 100); Self.SetShape(MyRegion); finally MyRegion.Free; end;
end; </delphi>
The result of this operation in a window in Mac OS X using the Qt widgetset can be see here:
Note that SetShape can also accept a TBitmap to describe the transparent region.
See also:
Documentation entries: