I am trying to have a functionality where a user will be able create a new button by clicking on the existing one on the form. Now, I am trying to achieve that by creating my own class called MyButton
that has a TButton
as an ancestor class.
The problem that I am having is that the new button is not showing on the Form after the existing button is clicked.
I have tried using the properties to set the needed values, as well as using the procedures that are stated in my class, but I always get the same three errors.
Here is the class that I have created:
unit clsButton;
interface
uses
vcl.StdCtrls, System.Classes;
type
myButton = class(TButton)
private
fTop, fLeft, fWidth, fHeight: Integer;
fCaption: String;
published
property top: Integer read fTop write fTop;
property left: Integer read fLeft write fLeft;
property width: Integer read fwidth write fWidth;
property height: Integer read fheight write fHeight;
property caption: String read fCaption write fCaption;
public
procedure setTop(value: Integer);
procedure setLeft(value: Integer);
procedure setWidth(value: Integer);
procedure setHeight(value: Integer);
procedure setCaption(value: String);
constructor Create();
end;
implementation
constructor myButton.Create;
begin
inherited Create(Self);
end;
procedure myButton.setTop(value: Integer);
begin
fTop := value;
end;
procedure myButton.setleft(value: Integer);
begin
fLeft := value;
end;
procedure myButton.setWidth(value: Integer);
begin
fWidth := value;
end;
procedure myButton.setHeight(value: Integer);
begin
fHeight := value;
end;
procedure myButton.setCaption(value: String);
begin
fCaption := value;
end;
end.
Here is the main unit where the OnClick
procedure is called in order to create a new button:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, clsButton;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
btn: myButton;
begin
btn := myButton.Create();
with btn do
begin
//top := 25;
//left := 25;
//height := 45;
//width := 50;
//caption := 'MyButton';
parent := self;
settop(25);
setLeft(25);
setheight(45);
setwidth(50);
setcaption('MyButton');
show;
end;
end;
end.
And here are the errors that I get after running the program:
Now, if I go to the class that I have created clsButton
and comment everything and then, in my main unit set the values of the properties by not using the setter methods (the block of code that is initially commented in the main unit), the new button shows on my Form having the caption value that I assigned... but, all other values are not the ones that I have given (top, left, width and height). Those are the values that Form1
has.
My guess is that I am mistaking somewhere in the constructor, but I can not figure it out.
UPDATE: I am adding the class I created based on what @Remy suggested in his coment:
unit clsButton;
interface
uses
System.Types, Vcl.StdCtrls, VCl.Forms, Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Dialogs;
type
myButton = class(Tbutton)
private
procedure setBounds(ALeft, ATop, AHeight, AWidth: Integer); override;
public
constructor Create(aOwner: TComponent); override;
end;
implementation
constructor myButton.Create;
begin
inherited create(AOwner);
end;
procedure myButton.setBounds(ALeft, ATop, AHeight, AWidth: Integer);
begin
inherited;
left := aLeft;
top := ATop;
height := AHeight;
width := AWidth;
end;
end.
This is also the OnButtonClick
event that should create a new button:
procedure TForm1.Button1Click(Sender: TObject);
var
p: myButton;
begin
p := mybutton.Create(self);
with p do
begin
parent := form1;
caption := 'MyButton';
setbounds(50, 85, 78, 92);
end;
end;
I still get the same errors....
Why are you introducing your own
left
/top
/width
/height
/caption
functionality inmyButton
? You are not assigning any values to the existing properties of the same names that are inherited fromTButton
. You really should be using the existing properties, and if you want your button to react to changes to those properties then you can override the virtualSetBounds()
method, and handle theCM_TEXTCHANGED
message, as needed.Also, why is
myButton
setting itself as its ownOwner
in its constructor? That is just plain wrong, and is likely why you are getting "stack overflow" errors at runtime, which will cause your button constructor to abort.Try this instead:
And then you need to fix
TForm1.Button1Click()
to use the correct constructor and properties, eg: