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....
CodePudding user response:
Why are you introducing your own left
/top
/width
/height
/caption
functionality in myButton
? You are not assigning any values to the existing properties of the same names that are inherited from TButton
. 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 virtual SetBounds()
method, and handle the CM_TEXTCHANGED
message, as needed.
Also, why is myButton
setting itself as its own Owner
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:
type
myButton = class(TButton)
protected
procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
end;
procedure myButton.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
inherited;
// do something...
end;
procedure myButton.CMTextChanged(var Message: TMessage);
begin
inherited;
// do something...
end;
And then you need to fix TForm1.Button1Click()
to use the correct constructor and properties, eg:
procedure TForm1.Button1Click(Sender: TObject);
var
btn: myButton;
begin
btn := myButton.Create(Self);
with btn do
begin
Parent := Self;
Top := 25;
Left := 25;
Height := 45;
Width := 50;
// or: SetBounds(25, 25, 50, 45);
Caption := 'MyButton';
Visible := True;
end;
end;
CodePudding user response:
So, with the help from @Remy, here is the code that I used and that solved my issue.
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
ftop, fleft, fheight, fwidth: Integer;
procedure setBounds(ALeft, ATop, AHeight, AWidth: Integer);override;
// procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
public
constructor Create(aOwner: TComponent);override;
end;
implementation
uses
unit1;
constructor myButton.Create(aowner: TComponent);
begin
inherited create(AOwner);
parent := form1;
top := ftop;
left := fleft;
height := fheight;
width := fwidth;
caption := 'MyButton';
end;
procedure myButton.setBounds(ALeft, ATop, AHeight, AWidth: Integer);
begin
inherited;
fleft := aLeft;
ftop := ATop;
fheight := AHeight;
fwidth := AWidth;
end;
end.
And here is the OnClick
that creates a new button
procedure TForm1.Button1Click(Sender: TObject);
var
p: myButton;
begin
p := mybutton.Create(self);
p.setbounds(50, 85, 78, 92);
end;