Recent

Author Topic: Creating draggable controls at run-time  (Read 2205 times)

Vodnik

  • Full Member
  • ***
  • Posts: 220
Creating draggable controls at run-time
« on: January 08, 2020, 09:14:55 am »
Hello,
Up to now I had to deal only with static controls, hiding and disabling them, etc.
Now customer asks for some kind of real-time report designer. The idea is that user can select some controls (e.g. TLabel) from the menu, place them on a form, change their size, font, color, etc. and link to a predefined variables from a list. Such freely designed form, when activated, should show how the selected variables change in real-time (e.g. number of calls, number of operators, etc.)
Question is: is there a necessary functionality available in Lazarus to create, edit and drag controls at run-time?
PS  I have read about FPReport Designer, seems it is a bit different thing.   

balazsszekely

  • Guest
Re: Creating draggable controls at run-time
« Reply #1 on: January 08, 2020, 09:48:21 am »
@Vodnik

You can create you're own custom control, but it's not a trivial task. A few years ago I converted the "SizeControl.pas" delphi unit(author: Angus Johnson) to lazarus. It was requested by a forum user, IIRC it only worked on windows. Please download the attached project and run a few test yourself. 
« Last Edit: January 08, 2020, 09:52:19 am by GetMem »

wp

  • Hero Member
  • *****
  • Posts: 13270
Re: Creating draggable controls at run-time
« Reply #2 on: January 08, 2020, 10:38:30 am »
A form designer component is contained in the JVCL library and has been ported to Lazarus. JVCLLaz is available via Online Package Manager. Run the demo JvDesigner in folder examples of the JVCLLaz installation. If you plan to use additional components for this designer you should search the forum where I explained the steps not too long ago; instructions are also given in the header of the main form unit of the demo.

Vodnik

  • Full Member
  • ***
  • Posts: 220
Re: Creating draggable controls at run-time
« Reply #3 on: January 08, 2020, 07:41:46 pm »
As I understand, the features I am asking about are not standard for Lazarus controls.

@Getmem, thank you for the SizeControl unit, I have just tested it. Controls resize and dragging work fine. What about creating controls at run-time? Is it possible in principle?

@wp, thanks, I learned a lot of new from your answer, just investigating.

sash

  • Sr. Member
  • ****
  • Posts: 366
Re: Creating draggable controls at run-time
« Reply #4 on: January 08, 2020, 11:10:31 pm »
What about creating controls at run-time? Is it possible in principle
This is the easiest part
Code: Pascal  [Select][+][-]
  1. MyControl := TLabel.Create(OwnerForm); // ownership
  2. MyControl.Parent := (SomePanelOrWhatever); //geometry
Lazarus 2.0.10 FPC 3.2.0 x86_64-linux-gtk2 @ Ubuntu 20.04 XFCE

Vodnik

  • Full Member
  • ***
  • Posts: 220
Re: Creating draggable controls at run-time
« Reply #5 on: January 09, 2020, 03:47:53 pm »
@Sash, thanks, but I didn't completely catch the idea. The following code cause no error, but MyLabel is not displayed on a form:
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
  6. type
  7.   { TForm1 }
  8.   TForm1 = class(TForm)
  9.     Label1: TLabel;
  10.   private
  11.   public
  12.   end;
  13. var
  14.   Form1: TForm1;
  15. implementation
  16. var MyLabel: TLabel;
  17. begin
  18. MyLabel := TLabel.create(Form1);
  19. MyLabel.Parent := Form1;
  20. MyLabel.Left:=100;
  21. MyLabel.Top:=100;
  22. {$R *.lfm}
  23. end.
  24.  

wp

  • Hero Member
  • *****
  • Posts: 13270
Re: Creating draggable controls at run-time
« Reply #6 on: January 09, 2020, 04:45:18 pm »
No this is not the way to do it. Your code between "begin" and "end" is in the initialization section of the unit - it is executed when the unit is loaded, at this moment the form does not yet exist. You can be lucky that this did not even crash the program.

This is the correct way:
  • Find the event "OnCreate" of the form and click on the ... button. Put your code in the code editor into the code skeleton which is created automatically.
  • The "TForm1" added in front of the name of the event handler indicates that this code is a "method" of TForm1, i.e. it can only be executed within an instance of the class TForm1. Therefore, refering to the form by its name "Form1" in "MyLabel := TLabel.Create(Form1)" is a bad idea - this will break the code when you somehow name the instance differently. It is much more versatile when you refer to the form by its general name "self".
  • Declare MyLabel as a private field of TForm1.
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
  9.  
  10. type
  11.   { TForm1 }
  12.   TForm1 = class(TForm)
  13.     procedure FormCreate(Sender: TObject);  // handler for the OnCreate event of the form
  14.   private
  15.     MyLabel: TLabel;      // <--- the label "belongs" to the form
  16.   public
  17.   end;
  18.  
  19. var
  20.   Form1: TForm1;
  21.  
  22. implementation
  23.  
  24. {$R *.lfm}
  25.  
  26. { TForm1 }
  27.  
  28. // This is executed when the form is created.
  29. procedure TForm1.FormCreate(Sender: TObject);
  30. begin
  31.   MyLabel := TLabel.Create(Self);   // Do not use the form variable name here. Use "self" instead of "Form1"
  32.   MyLabel.Parent := self;   // dto.
  33.   MyLabel.Left := 100;
  34.   MyLabel.Top := 100;
  35.   MyLabel.Caption := 'Hello world';   // Set the caption of the label - an empty string cannot be seen.
  36. end;
  37.  
  38. end.

Complete compilable project in the attachment

Vodnik

  • Full Member
  • ***
  • Posts: 220
Re: Creating draggable controls at run-time
« Reply #7 on: January 09, 2020, 10:19:15 pm »
Wp, great respect for your code, explanation and patience...
I modified the code to allow the application user to add some Labels when the form is already created:
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Menus;
  6. type
  7.   { TForm1 }
  8.   TForm1 = class(TForm)
  9.     MainMenu1: TMainMenu;
  10.     MenuItem1: TMenuItem;
  11.     procedure MenuItem1Click(Sender: TObject);
  12.   private
  13.     MyLabels: array[1..10] of TLabel;
  14.   public
  15.   end;
  16. var
  17.   Form1: TForm1;
  18.   I: integer = 1;
  19. implementation
  20. {$R *.lfm}
  21. { TForm1 }
  22. procedure TForm1.MenuItem1Click(Sender: TObject);
  23. begin
  24.   if I>10 then exit;
  25.   MyLabels[I]:=TLabel.Create(Self);
  26.   MyLabels[I].Parent:=self;
  27.   MyLabels[I].Left := 20;
  28.   MyLabels[I].Top := 20*I;
  29.   MyLabels[I].Caption := 'Hello world '+IntToStr(I);
  30.   Inc(I);
  31. end;
  32. end.
  33.  

soerensen3

  • Full Member
  • ***
  • Posts: 213
Re: Creating draggable controls at run-time
« Reply #8 on: January 10, 2020, 04:46:43 pm »
You can also have a look at pl_ExDesign. It does what you want, but I'm not sure about the license (obviously the author is from the codetyphon project. You can download it via the online package manager. There are also examples include.
Lazarus 1.9 with FPC 3.0.4
Target: Manjaro Linux 64 Bit (4.9.68-1-MANJARO)

 

TinyPortal © 2005-2018