Recent

Author Topic: Replace controls dynamically on a form  (Read 1303 times)

Tikani93

  • Newbie
  • Posts: 4
Replace controls dynamically on a form
« on: June 18, 2025, 11:36:08 pm »
I have a Lazarus Win32 project, which has a TForm, crafted in IDE visually (i.e. there is the .lfm file in the project folder). I want, when some condition is met in a code, remove a TButton and replace it with a TProgressBar in a 1-1 fashion (the TProgressBar must have the same size, position, and anchors, like TButton had before deletion).
Sorry, if something sounds strange or silly, English is not my native language.

Aruna

  • Hero Member
  • *****
  • Posts: 666
Re: Replace controls dynamically on a form
« Reply #1 on: June 18, 2025, 11:58:42 pm »
I have a Lazarus Win32 project, which has a TForm, crafted in IDE visually (i.e. there is the .lfm file in the project folder). I want, when some condition is met in a code, remove a TButton and replace it with a TProgressBar in a 1-1 fashion (the TProgressBar must have the same size, position, and anchors, like TButton had before deletion).
Sorry, if something sounds strange or silly, English is not my native language.
Your question is perfectly clear, and your English is great — no need to apologize! Here’s how to replace a TButton with a TProgressBar at runtime in Lazarus, keeping the same size, position, and anchors. A fully working demo zip is attached.

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, ComCtrls;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Button1: TButton;
  16.     ButtonReplace: TButton;
  17.  
  18.     procedure ButtonReplaceClick(Sender: TObject);
  19.   private
  20.     ProgressBar: TProgressBar; // Will hold the new progress bar
  21.     procedure ReplaceButtonWithProgressBar;
  22.   public
  23.  
  24.   end;
  25.  
  26. var
  27.   Form1: TForm1;
  28.  
  29. implementation
  30.  
  31. {$R *.lfm}
  32.  
  33. procedure TForm1.ButtonReplaceClick(Sender: TObject);
  34. begin
  35.   ReplaceButtonWithProgressBar;
  36. end;
  37.  
  38. procedure TForm1.ReplaceButtonWithProgressBar;
  39. begin
  40.   // Check if the button exists and hasn't been replaced yet
  41.   if Assigned(Button1) then
  42.   begin
  43.     // Create and configure a new TProgressBar
  44.     ProgressBar := TProgressBar.Create(Self);
  45.     ProgressBar.Parent := Button1.Parent;
  46.  
  47.     // Copy the button's position, size, and anchors
  48.     ProgressBar.SetBounds(Button1.Left, Button1.Top, Button1.Width, Button1.Height);
  49.     ProgressBar.Anchors := Button1.Anchors;
  50.  
  51.     // Optional settings
  52.     ProgressBar.Min := 0;
  53.     ProgressBar.Max := 100;
  54.     ProgressBar.Position := 50; // Example: halfway
  55.  
  56.     // Remove and free the original button
  57.     Button1.Free;
  58.     Button1 := nil;
  59.   end;
  60. end;
  61.  
  62. end.
  63.  
  64.  
  65.  

CM630

  • Hero Member
  • *****
  • Posts: 1436
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Replace controls dynamically on a form
« Reply #2 on: June 19, 2025, 11:15:01 am »
A simpler solution - create both controls (button and progress bar) in the IDE in design mode.
Set ProgressBar1.Visible to False.
In the code do:
Code: Pascal  [Select][+][-]
  1. Button1.Visible := False;
  2. ProgressBar1.Visible := True;
  3.  
Лазар 4,0 32 bit (sometimes 64 bit); FPC3,2,2

Aruna

  • Hero Member
  • *****
  • Posts: 666
Re: Replace controls dynamically on a form
« Reply #3 on: June 19, 2025, 11:43:10 pm »
A simpler solution - create both controls (button and progress bar) in the IDE in design mode.
Set ProgressBar1.Visible to False.
In the code do:
Code: Pascal  [Select][+][-]
  1. Button1.Visible := False;
  2. ProgressBar1.Visible := True;
  3.  
The OP wanted to: Replace controls dynamically on a form  8-)

n7800

  • Sr. Member
  • ****
  • Posts: 399
Re: Replace controls dynamically on a form
« Reply #4 on: June 20, 2025, 02:11:39 am »
Here’s how to replace a TButton with a TProgressBar at runtime in Lazarus, keeping the same size, position, and anchors. A fully working demo zip is attached.

In common case, it's more complicated than it seems. I haven't tested this code, just wanted to share some info (expanding on the author's specific question):
* Will this code restore the Z-order of the component? The order of the controls may affect the display, if they overlap or use ChildSizing.
* Will it restore the TabOrder value? Because of this, the [Tab] key navigation may go in a different order.
* Will it work when using Align? Different controls may be reordered when the direction is the same.
* Will it work when using ChildSizing? By the way, it also depends on the Z-order.
* Other huge number of nuances AutoSize, Constraints, BorderSpacing...

I'm sure everyone will find a lot of new information on this wiki page.

n7800

  • Sr. Member
  • ****
  • Posts: 399
Re: Replace controls dynamically on a form
« Reply #5 on: June 20, 2025, 02:16:21 am »
There is also a very interesting error in the code (very subtle if you don't know the implementation details) - the component is destroyed in its own event. I couldn't find a link where I read about it, but here is a similar topic, and some notes in the Delphi documentation.

Release should be used instead of Free. However, even this can have side effects (at least because of the Button1 reference).

EDITED: There is no error in this code, because one button causes the destruction of another. As I said above, I did not test it, but just wanted to share useful knowledge.
« Last Edit: June 20, 2025, 03:39:56 am by n7800 »

n7800

  • Sr. Member
  • ****
  • Posts: 399
Re: Replace controls dynamically on a form
« Reply #6 on: June 20, 2025, 02:24:11 am »
In any case, from a practical point of view, there is too much code for such a task. Therefore, I also support a simpler way of implementation:

A simpler solution - create both controls (button and progress bar) in the IDE in design mode.
Set ProgressBar1.Visible to False.
In the code do:
Code: Pascal  [Select][+][-]
  1. Button1.Visible := False;
  2. ProgressBar1.Visible := True;
  3.  

It can be done even more simply, if you create a TPanel, for which you specify bindings and other positioning parameters. And in it you can simply place controls with "Align:=alClient".

Or still create/destroy controls in it, but without problems with bindings. But it is worth remembering that recreating components is an expensive operation, for speed and resources. And as was said, due to the risks of pointer obsolescence.

Aruna

  • Hero Member
  • *****
  • Posts: 666
Re: Replace controls dynamically on a form
« Reply #7 on: June 20, 2025, 02:57:40 am »
There is also a very interesting error in the code (very subtle if you don't know the implementation details) - the component is destroyed in its own event. I couldn't find a link where I read about it, but here is a similar topic, and some notes in the Delphi documentation.

Release should be used instead of Free. However, even this can have side effects (at least because of the Button1 reference).
If you go through the code and check carefully the event handler is ButtonReplaceClick, and the button being destroyed is Button1, not the one being clicked.
Therefore: ButtonReplace is the button being clicked, and it's the one whose OnClick is being handled.

Button1 is just another button on the form, and it’s being destroyed inside ReplaceButtonWithProgressBar, but not in its own event.

Aruna

  • Hero Member
  • *****
  • Posts: 666
Re: Replace controls dynamically on a form
« Reply #8 on: June 20, 2025, 03:04:38 am »
The attached screenshot will help clear up the two event handlers and it would be nice if either/both of you or anyone else instead of simply saying this is simpler actually provide a full working unit which clearly demonstrates what your describing as simpler and preferably heavily comment so a newbie will not have a hard time understanding as in this case the OP said English is not his/her first language.

n7800

  • Sr. Member
  • ****
  • Posts: 399
Re: Replace controls dynamically on a form
« Reply #9 on: June 20, 2025, 04:02:34 am »
If you go through the code and check carefully the event handler is ButtonReplaceClick, and the button being destroyed is Button1, not the one being clicked.
Therefore: ButtonReplace is the button being clicked, and it's the one whose OnClick is being handled.

Button1 is just another button on the form, and it’s being destroyed inside ReplaceButtonWithProgressBar, but not in its own event.

Sorry, I really didn't notice that these are different buttons. As I said, I haven't tested the code, and just wanted to share my knowledge. Of course, to avoid misunderstandings, I have edited the comment, and I hope that will be forgiven ))

But reading the author's question, I assume that he wants to place a button to start some process, and when clicked, a progress bar will appear. Therefore, I specified that the button cannot be destroyed from its own click event.

n7800

  • Sr. Member
  • ****
  • Posts: 399
Re: Replace controls dynamically on a form
« Reply #10 on: June 20, 2025, 05:15:50 am »
The attached screenshot will help clear up the two event handlers and it would be nice if either/both of you or anyone else instead of simply saying this is simpler actually provide a full working unit which clearly demonstrates what your describing as simpler and preferably heavily comment so a newbie will not have a hard time understanding as in this case the OP said English is not his/her first language.

I am glad to see that the forum cares so much about newcomers. As you can see, I also took the time to write detailed comments in the messages.

I hope that two lines of code do not require a example project. As for the design, in other words: instead of a button, you need to create a panel, and place a TButton and TProgressBar in it (with Align:=alClient). In the code, make one or the other visible via "Visible".

Let's see if our suggestions were clear to the author and if they are suitable...

Zvoni

  • Hero Member
  • *****
  • Posts: 3003
Re: Replace controls dynamically on a form
« Reply #11 on: June 20, 2025, 08:11:40 am »
I am glad to see that the forum cares so much about newcomers. As you can see, I also took the time to write detailed comments in the messages.
Agreed.
Neverthless, especially for Newcomers the old hands answering/helping said newcomer have to be like diplomats:
"Listen to what the other party wants, and then identifiy, what the other party actually needs."
as in: "I want to replace a control dynamically" vs. "place both on the form, and then hide one as needed"

So, an answer "This is simpler" is a valid answer, provided the "Problem" has been identified correctly.

Everything said: I agree with the "simpler" way: place both controls on the Form, and then just toggle visibility.
No need to jump through burning hoops regarding event-handlers and what not.
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

Aruna

  • Hero Member
  • *****
  • Posts: 666
Re: Replace controls dynamically on a form
« Reply #12 on: June 20, 2025, 11:01:22 am »
If you go through the code and check carefully the event handler is ButtonReplaceClick, and the button being destroyed is Button1, not the one being clicked.
Therefore: ButtonReplace is the button being clicked, and it's the one whose OnClick is being handled.

Button1 is just another button on the form, and it’s being destroyed inside ReplaceButtonWithProgressBar, but not in its own event.

Sorry, I really didn't notice that these are different buttons. As I said, I haven't tested the code, and just wanted to share my knowledge. Of course, to avoid misunderstandings, I have edited the comment, and I hope that will be forgiven ))
There is no need to apologize you were trying to help. You just had not tested the code yet.  It is just that folks tend to forget we were all *newbies* at one point in our lives. And I am now weary of seeing people ask questions and not get useful nor helpful answers and guidance but a 'That is not how you do things' or 'This is bad code' or an answer with information that is way above and beyond  a new comers level of knowledge or familiarity with the IDE which in turn causes frustration and most folks will never want to come back?

Also, No offence and no disrespect but the knowledge you shared below:

* Will this code restore the Z-order of the component? The order of the controls may affect the display, if they overlap or use ChildSizing.
* Will it restore the TabOrder value? Because of this, the [Tab] key navigation may go in a different order.
* Will it work when using Align? Different controls may be reordered when the direction is the same.
* Will it work when using ChildSizing? By the way, it also depends on the Z-order.
* Other huge number of nuances AutoSize, Constraints, BorderSpacing...

How many new comers will really understand what it is your trying to tell them? This will not help a newbie this only demoralizes, demotivates and we lose a developer. Not good. When someone has *your* kind of experience and expertise yes that is a solid useful helpful response but in a newbies situation that will only help them to leave and fast.

This reminds me I recently had trouble with Z-order and I am using Linux Debian with Lazarus 4 and I was trying to move a Timage to the front of a TMemo but was unable to do so. Later investigations with other components gave the same result Z-order is not honored or functional in design mode. I am not sure if I should open a new thread or investigate this further?


n7800

  • Sr. Member
  • ****
  • Posts: 399
Re: Replace controls dynamically on a form
« Reply #13 on: June 20, 2025, 02:42:14 pm »
I already provided a link with details, if the author is interested. And I remember very well how as a newbie I once read it and found many new ways to align components.

By the way, the forum is not only read by "newbies". I also learned a lot from reading other people's answers, even in "random" topics. In any case, it is easier to "filter" unnecessary information than to compensate for its lack.

I see that you have already been answered about the problem with the Z-order of TImage.

Aruna

  • Hero Member
  • *****
  • Posts: 666
Re: Replace controls dynamically on a form
« Reply #14 on: June 22, 2025, 03:40:02 pm »
I already provided a link with details, if the author is interested. And I remember very well how as a newbie I once read it and found many new ways to align components.

By the way, the forum is not only read by "newbies". I also learned a lot from reading other people's answers, even in "random" topics. In any case, it is easier to "filter" unnecessary information than to compensate for its lack.

I see that you have already been answered about the problem with the Z-order of TImage.
Hello @n7800 I am sorry for the way I responded that day it was one of those days and I was under a lot of pressure and stress so I am sorry if I said anything that hurt your feelings. And yes I was helped out about the problem with the Timage seems it is a graphics thing does not have a handle so you must give it a parent then Z-order is respected.

 

TinyPortal © 2005-2018