Recent

Author Topic: Create components and order them at runtime  (Read 816 times)

valter.home

  • New Member
  • *
  • Posts: 32
Create components and order them at runtime
« on: September 22, 2020, 06:26:51 pm »
Hi everyone.
it seems nonsense but I can't figure it out.
I need to create components at runtime but I can't place them correctly.
I should have in order: a TLabel, a TMemo, a TLabel and a TFilenameEdit.
I was able to get this sequence only by using a TPanel for each component but it seems a waste to me.
I'll give you a simple code example:

Code: Pascal  [Select][+][-]
  1. Caption1:= TLabel.Create(PanelContainer);
  2. Caption1.Parent:=PanelContainer;
  3. Caption1.Caption:='Caption 1';
  4. Caption1.AutoSize:=True;
  5. Caption1.Align:=alBottom;
  6.  
  7. Memo1 := TMemo.Create(PanelContainer);
  8. Memo1.Parent:=PanelContainer;
  9. Memo1.Height:=40;
  10. Memo1.Align:=alBottom;
  11. Memo1.ScrollBars:=ssAutoBoth;
  12. Memo1.Clear;
  13.  
  14. Caption2:= TLabel.Create(PanelContainer);
  15. Caption2.Parent:=PanelContainer;
  16. Caption2.Caption:='Caption 2';
  17. Caption2.AutoSize:=True;
  18. Caption2.Align:=alBottom;
  19.  
  20. LoadFile := TFilenameEdit.Create(PanelContainer);
  21. LoadFile.Parent:=PanelContainer;
  22. LoadFile.Align:=alBottom;
  23. LoadFile.Text:=String.Empty;

Of course this is just an example, I tried to modify it several times by setting for example the Top parameter of a component below the Top + Height of the above component and then setting Align to AlBottom hoping that it would remain below the one above.
It happens that the TLabels gather together and do not hold the position of creation.
These components are located on one side of a TSplitter so they must also resize when it is moved.
In short, have you ever found yourself in this situation and how did you solve it?

Handoko

  • Hero Member
  • *****
  • Posts: 3901
  • My goal: build my own game engine using Lazarus
Re: Create components and order them at runtime
« Reply #1 on: September 22, 2020, 06:39:53 pm »
It happens that the TLabels gather together and do not hold the position of creation.

If I understood what you want correctly, I believe you should set the values of BolderSpacing property.

These components are located on one side of a TSplitter so they must also resize when it is moved.

I believe it can be achieve by 2 panels + a splitter, for example the first panel is set to Align := alLeft, then a spliter which also Align := alLeft and the last panel should be Align := alClient;

valter.home

  • New Member
  • *
  • Posts: 32
Re: Create components and order them at runtime
« Reply #2 on: September 22, 2020, 07:07:01 pm »
Quote
If I understood what you want correctly, I believe you should set the values of BolderSpacing property.

Hi, thanks for your reply. I probably explained myself badly.
What happens is that I create the 4 components mentioned above at runtime but they do not respect the creation sequence.

TLabel then TMemo then TLabel and finally TFilenameEdit.

Each of them must be on top of the other, for this use Align: = AlBottom.
Instead I get TLabel, TLabel, TMemo and TFilenameEdit
or
TLabel, TFilenameEdit, TLabel and TMemo.

It appears that the components are placed randomly.

Quote
I believe it can be achieve by 2 panels + a splitter

This part works well, I pointed out that there is a TSplitter to explain why I use Align for components.


Blaazen

  • Hero Member
  • *****
  • Posts: 2994
  • POKE 54296,15
    • Eye-Candy Controls
Re: Create components and order them at runtime
« Reply #3 on: September 22, 2020, 07:16:21 pm »
Use Anchors instead of Align. You will have better control over your components.
Lazarus 2.1.0 r64115 FPC 3.3.1 r40507 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

Handoko

  • Hero Member
  • *****
  • Posts: 3901
  • My goal: build my own game engine using Lazarus
Re: Create components and order them at runtime
« Reply #4 on: September 22, 2020, 07:21:13 pm »
It works on my test on Linux GTK2. Download and run my code and see is that what you want.

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, ExtCtrls, StdCtrls, EditBtn;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Button1: TButton;
  16.     PanelContainer: TPanel;
  17.     procedure Button1Click(Sender: TObject);
  18.     procedure FormCreate(Sender: TObject);
  19.   end;
  20.  
  21. var
  22.   Form1: TForm1;
  23.  
  24. implementation
  25.  
  26. {$R *.lfm}
  27.  
  28. { TForm1 }
  29.  
  30. procedure TForm1.Button1Click(Sender: TObject);
  31. var
  32.   Caption1, Caption2: TLabel;
  33.   Memo1: TMemo;
  34.   LoadFile: TFilenameEdit;
  35. begin
  36.   Caption1:= TLabel.Create(PanelContainer);
  37.   Caption1.Parent:=PanelContainer;
  38.   Caption1.Caption:='Caption 1';
  39.   Caption1.AutoSize:=True;
  40.   Caption1.Align:=alBottom;
  41.  
  42.   Memo1 := TMemo.Create(PanelContainer);
  43.   Memo1.Parent:=PanelContainer;
  44.   Memo1.Height:=40;
  45.   Memo1.Align:=alBottom;
  46.   Memo1.ScrollBars:=ssAutoBoth;
  47.   Memo1.Clear;
  48.  
  49.   Caption2:= TLabel.Create(PanelContainer);
  50.   Caption2.Parent:=PanelContainer;
  51.   Caption2.Caption:='Caption 2';
  52.   Caption2.AutoSize:=True;
  53.   Caption2.Align:=alBottom;
  54.  
  55.   LoadFile := TFilenameEdit.Create(PanelContainer);
  56.   LoadFile.Parent:=PanelContainer;
  57.   LoadFile.Align:=alBottom;
  58.   LoadFile.Text:=String.Empty;
  59. end;
  60.  
  61. procedure TForm1.FormCreate(Sender: TObject);
  62. begin
  63.   PanelContainer.Anchors := [akTop, akBottom, akLeft, akRight];
  64. end;
  65.  
  66. end.

valter.home

  • New Member
  • *
  • Posts: 32
Re: Create components and order them at runtime
« Reply #5 on: September 22, 2020, 09:04:03 pm »
Your exact same code with Lazarus 2.0.10 under Windows 10 places the components in this order from the top: Caption1, LoadFile, Caption2, Memo. I do not understand.


howardpc

  • Hero Member
  • *****
  • Posts: 3579
Re: Create components and order them at runtime
« Reply #6 on: September 22, 2020, 09:48:45 pm »
As Blaazen wrote, anchors give you the fine control you need.
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   Caption1, Caption2: TLabel;
  4.   Memo1: TMemo;
  5.   LoadFile: TFilenameEdit;
  6. begin
  7.   Caption1 := TLabel.Create(PanelContainer);
  8.   Caption1.Caption := 'Caption 1';
  9.   Caption1.AnchorSideLeft.Control := PanelContainer;
  10.   Caption1.AnchorSideTop.Control := PanelContainer;
  11.   Caption1.Parent:=PanelContainer;
  12.  
  13.   Memo1 := TMemo.Create(PanelContainer);
  14.   Memo1.Height := 40;
  15.   Memo1.ScrollBars := ssAutoBoth;
  16.   Memo1.Clear;
  17.   Memo1.Anchors := [akLeft, akTop, akRight];
  18.   Memo1.AnchorSideTop.Control := Caption1;
  19.   Memo1.AnchorSideTop.Side := asrBottom;
  20.   Memo1.AnchorSideLeft.Control := PanelContainer;
  21.   Memo1.AnchorSideRight.Control := PanelContainer;
  22.   Memo1.AnchorSideRight.Side := asrRight;
  23.   Memo1.Parent := PanelContainer;
  24.  
  25.   Caption2:= TLabel.Create(PanelContainer);
  26.   Caption2.Caption:='Caption 2';
  27.   Caption2.AnchorSideLeft.Control := PanelContainer;
  28.   Caption2.AnchorSideTop.Control := Memo1;
  29.   Caption2.AnchorSideTop.Side := asrBottom;
  30.   Caption2.Parent:=PanelContainer;
  31.  
  32.   LoadFile := TFilenameEdit.Create(PanelContainer);
  33.   LoadFile.Anchors := [akLeft, akTop, akRight];
  34.   LoadFile.AnchorSideLeft.Control := PanelContainer;
  35.   LoadFile.AnchorSideTop.Control := Caption2;
  36.   LoadFile.AnchorSideTop.Side := asrBottom;
  37.   LoadFile.AnchorSideRight.Control := PanelContainer;
  38.   LoadFile.AnchorSideRight.Side := asrRight;
  39.   LoadFile.Text:=String.Empty;
  40.   LoadFile.Parent:=PanelContainer;
  41. end;
You probably will want additional settings for BorderSpacing properties to improve the layout, as Handoko suggests.

Handoko

  • Hero Member
  • *****
  • Posts: 3901
  • My goal: build my own game engine using Lazarus
Re: Create components and order them at runtime
« Reply #7 on: September 22, 2020, 10:03:19 pm »
Your exact same code with Lazarus 2.0.10 under Windows 10 places the components in this order from the top: Caption1, LoadFile, Caption2, Memo. I do not understand.

I use Ubuntu Mate Lazarus 2.0.10 GTK2, I did not test the code on Windows. If if behaves differently then it should be OS related issue. You can submit the issue to the bugtracker:
http://bugs.freepascal.org/view_all_bug_page.php?project_id=1

valter.home

  • New Member
  • *
  • Posts: 32
Re: Create components and order them at runtime
« Reply #8 on: September 22, 2020, 10:23:51 pm »
Quote
As Blaazen wrote, anchors give you the fine control you need.

Thanks so much.
I was just working on Blaazen's suggestion but coming from Unity I was browsing through the various options, you really helped me by saving me a lot of time. Thanks again.

valter.home

  • New Member
  • *
  • Posts: 32
Re: Create components and order them at runtime
« Reply #9 on: September 22, 2020, 10:54:34 pm »
Quote
You can submit the issue to the bugtracker

Yes, Howardpc's code definitely solves the problem but it's a shame not to be able to insert components in sequence simply by creating them.
I tried to replace the 4 components with four TPanels. They are shown  with this sequence: 1 - 4 - 3 - 2.


jamie

  • Hero Member
  • *****
  • Posts: 3774
Re: Create components and order them at runtime
« Reply #10 on: September 23, 2020, 02:34:37 am »
You could always look at TFowPanel control.
The only true wisdom is knowing you know nothing

eny

  • Hero Member
  • *****
  • Posts: 1613
Re: Create components and order them at runtime
« Reply #11 on: September 23, 2020, 10:01:01 am »
In short, have you ever found yourself in this situation and how did you solve it?
Unfortunately, yes.
And you will be in a whole new world of pain when you start hiding and unhiding components and want to retain a certain ordering :D
Anchors, as suggested by Blaazen and explained by Howardpc, work quite well in Lazarus.
All posts based on: Win10 (Win64); Lazarus 2.0.10 'stable' (x64) unless specified otherwise...

valter.home

  • New Member
  • *
  • Posts: 32
Re: Create components and order them at runtime
« Reply #12 on: September 23, 2020, 12:26:22 pm »
Quote
You could always look at TFowPanel control.

I did not know this component, it is great for maintaining the order of the components within it but I think I understand that the Align and Anchors properties are ignored. In this case, by resizing the panel they would not remain anchored to the right. In any case, thanks for letting me discover an interesting component. I should take some time and go through all them.

JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3883
  • I like bugs.
Re: Create components and order them at runtime
« Reply #13 on: September 23, 2020, 01:10:03 pm »
Yes, anchors is the way to go. The Lazarus / LCL layout system is vastly enhanced from Delphi's simple system with Align property.
The AnchorSide... and BorderSpacing properties require some learning and they may not appear intuitive always.
A good strategy is to build a layout in form designer. Then if you must create the controls + layout in code, just copy the relevant parts from the .lfm file, replace '=' with ':=' and add ';' to the end.
I actually just did that for the file / dependency properties GUI in the PackageEditor window, but did not commit yet.
In designer the controls were on top of each other and difficult to maintain.
The code will be partly reused for ProjectInspector window later.
See:
Code: Pascal  [Select][+][-]
  1.   // file properties
  2.   // ---------------
  3.   CallRegisterProcCheckBox := TCheckBox.Create(fOwner);
  4.   CallRegisterProcCheckBox.Parent := fOwner;
  5.   CallRegisterProcCheckBox.Left := 6;
  6.   CallRegisterProcCheckBox.Top := 0;
  7.   CallRegisterProcCheckBox.Width := 185;
  8.   CallRegisterProcCheckBox.ShowHint := True;
  9.   CallRegisterProcCheckBox.TabOrder := 0;
  10.   CallRegisterProcCheckBox.Caption := lisPckEditRegisterUnit;
  11.   CallRegisterProcCheckBox.Hint := Format(lisPckEditCallRegisterProcedureOfSelectedUnit, ['"', '"']);
  12.  
  13.   AddToUsesPkgSectionCheckBox := TCheckBox.Create(fOwner);
  14.   AddToUsesPkgSectionCheckBox.Parent := fOwner;
  15.   AddToUsesPkgSectionCheckBox.AnchorSideLeft.Control := CallRegisterProcCheckBox;
  16.   AddToUsesPkgSectionCheckBox.AnchorSideLeft.Side := asrBottom;
  17.   AddToUsesPkgSectionCheckBox.Left := 195;
  18.   AddToUsesPkgSectionCheckBox.Top := 0;
  19.   AddToUsesPkgSectionCheckBox.Width := 222;
  20.   AddToUsesPkgSectionCheckBox.BorderSpacing.Left := 10;
  21.   AddToUsesPkgSectionCheckBox.ShowHint := True;
  22.   AddToUsesPkgSectionCheckBox.TabOrder := 1;
  23.   AddToUsesPkgSectionCheckBox.Caption := lisPkgMangUseUnit;
  24.   AddToUsesPkgSectionCheckBox.Hint := lisPkgMangAddUnitToUsesClause;
  25.  
  26.   RegisteredPluginsGroupBox := TGroupBox.Create(fOwner);
  27.   RegisteredPluginsGroupBox.Parent := fOwner;
  28.   RegisteredPluginsGroupBox.Left := 3;
  29.   RegisteredPluginsGroupBox.Height := 165;
  30.   RegisteredPluginsGroupBox.Top := 27;
  31.   RegisteredPluginsGroupBox.Width := 452;
  32.   RegisteredPluginsGroupBox.Align := alBottom;
  33.   RegisteredPluginsGroupBox.Anchors := [akTop, akLeft, akRight, akBottom];
  34.   RegisteredPluginsGroupBox.BorderSpacing.Top := 6;
  35.   RegisteredPluginsGroupBox.TabOrder := 7;
  36.   RegisteredPluginsGroupBox.Caption := lisPckEditRegisteredPlugins;
  37.  
  38.   RegisteredListBox := TListBox.Create(fOwner);
  39.   RegisteredListBox.Parent := RegisteredPluginsGroupBox;
  40.   RegisteredListBox.Align := alClient;
  41.   RegisteredListBox.ScrollWidth := 448;
  42.   RegisteredListBox.Style := lbOwnerDrawFixed;
  43.   RegisteredListBox.TabOrder := 0;
  44.   RegisteredListBox.ItemHeight := ComponentPaletteImageHeight;
  45.  
  46.   // dependency properties
  47.   // ---------------------
  48.   UseMinVersionCheckBox := TCheckBox.Create(fOwner);
  49.   UseMinVersionCheckBox.Parent := fOwner;
  50.   UseMinVersionCheckBox.AnchorSideTop.Control := MinVersionEdit;
  51.   UseMinVersionCheckBox.AnchorSideTop.Side := asrCenter;
  52.   UseMinVersionCheckBox.Left := 6;
  53.   UseMinVersionCheckBox.Top := 6;
  54.   UseMinVersionCheckBox.Width := 179;
  55.   UseMinVersionCheckBox.TabOrder := 2;
  56.   UseMinVersionCheckBox.Caption := lisPckEditMinimumVersion;
  57.   UseMinVersionCheckBox.OnChange := @UseMinVersionCheckBoxChange;
  58.  
  59.   MinVersionEdit := TEdit.Create(fOwner);
  60.   MinVersionEdit.Parent := fOwner;
  61.   MinVersionEdit.AnchorSideLeft.Control := UseMinVersionCheckBox;
  62.   MinVersionEdit.AnchorSideLeft.Side := asrBottom;
  63.   MinVersionEdit.Left := 201;
  64.   MinVersionEdit.Top := 0;
  65.   MinVersionEdit.Width := 100;
  66.   MinVersionEdit.BorderSpacing.Left := 10;
  67.   MinVersionEdit.TabOrder := 3;
  68.   MinVersionEdit.OnChange := @MinMaxVersionEditChange;
  69.  
  70.   UseMaxVersionCheckBox := TCheckBox.Create(fOwner);
  71.   UseMaxVersionCheckBox.Parent := fOwner;
  72.   UseMaxVersionCheckBox.AnchorSideTop.Control := MaxVersionEdit;
  73.   UseMaxVersionCheckBox.AnchorSideTop.Side := asrCenter;
  74.   UseMaxVersionCheckBox.Left := 6;
  75.   UseMaxVersionCheckBox.Top := 43;
  76.   UseMaxVersionCheckBox.Width := 182;
  77.   UseMaxVersionCheckBox.TabOrder := 4;
  78.   UseMaxVersionCheckBox.Caption := lisPckEditMaximumVersion;
  79.   UseMaxVersionCheckBox.OnChange := @UseMaxVersionCheckBoxChange;
  80.  
  81.   MaxVersionEdit := TEdit.Create(fOwner);
  82.   MaxVersionEdit.Parent := fOwner;
  83.   MaxVersionEdit.AnchorSideLeft.Control := UseMaxVersionCheckBox;
  84.   MaxVersionEdit.AnchorSideLeft.Side := asrBottom;
  85.   MaxVersionEdit.AnchorSideTop.Control := MinVersionEdit;
  86.   MaxVersionEdit.AnchorSideTop.Side := asrBottom;
  87.   MaxVersionEdit.Left := 204;
  88.   MaxVersionEdit.Top := 38;
  89.   MaxVersionEdit.Width := 100;
  90.   MaxVersionEdit.BorderSpacing.Left := 10;
  91.   MaxVersionEdit.BorderSpacing.Top := 2;
  92.   MaxVersionEdit.TabOrder := 5;
  93.   MaxVersionEdit.OnChange := @MinMaxVersionEditChange;
  94.  
  95.   ApplyDependencyButton := TButton.Create(fOwner);
  96.   ApplyDependencyButton.Parent := fOwner;
  97.   ApplyDependencyButton.AnchorSideTop.Control := MaxVersionEdit;
  98.   ApplyDependencyButton.AnchorSideTop.Side := asrBottom;
  99.   ApplyDependencyButton.Left := 6;
  100.   ApplyDependencyButton.Top := 80;
  101.   ApplyDependencyButton.AutoSize := True;
  102.   ApplyDependencyButton.BorderSpacing.Top := 6;
  103.   ApplyDependencyButton.TabOrder := 6;
  104.   ApplyDependencyButton.Caption := lisPckEditApplyChanges;
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux.

Blaazen

  • Hero Member
  • *****
  • Posts: 2994
  • POKE 54296,15
    • Eye-Candy Controls
Re: Create components and order them at runtime
« Reply #14 on: September 23, 2020, 02:09:14 pm »
One note to Anchoring by code, see the attached screenshot.

The equivalents are:
the left button: AnchorParallel
Code: Pascal  [Select][+][-]
  1. Button1.AnchorParallel(akLeft, 0, Button2);

the middle button: AnchorHorizontalCenterTo (or AnchorVerticalCenterTo)
Code: Pascal  [Select][+][-]
  1. Button1.AnchorHorizontalCenterTo(Button2);

the right button: AnchorToNeighbour
Code: Pascal  [Select][+][-]
  1. Button1.AnchorToNeighbour(akLeft, 0, Button2);

There is also method AnchorToCompanion, where
Code: Pascal  [Select][+][-]
  1.   Button1.AnchorToCompanion(akLeft, 5, Button2);
is combination of
Code: Pascal  [Select][+][-]
  1.   Button1.AnchorToNeighbour(akLeft, 5, Button2);
  2.   Button1.AnchorParallel(akTop, 0, Button2);
  3.   Button1.AnchorParallel(akBottom, 0, Button2);
Lazarus 2.1.0 r64115 FPC 3.3.1 r40507 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

 

TinyPortal © 2005-2018