Reputation: 63
I am subclassing TGridPanel
to my control TMyGridPanel
.
I do this because i want to add 4 default buttons in the GridPanel
.
So i override the constructor
and create the buttons like:
constructor TMyGridPanel.Create(AOwner: TComponent);
var
i: Integer;
btn: TButton;
begin
inherited Create(AOwner);
for i := 0 to 3 do
begin
btn := TButton.Create(Self);
btn.Parent := Self;
btn.Align := alClient;
btn.Caption := 'Hello World';
btn.Visible := True;
end;
end;
This is working fine.
The ControlCollection
Items property shows 4 Buttons as CollectionItems
.
Now i want to copy and paste (duplicate) my control because i want to have 2 of it. However when i do it the buttons don't show up in the control.
The ControlCollection
Items property shows 4 Collection Items but they don't have a name (empty).
When i close the form and reopen it the buttons appear.
I am trying to fix this problem for some days now but can't figure it out.
Upvotes: 4
Views: 517
Reputation: 5448
When you copy your panel component to clipboard, all its published properties are streamed into text (paste it in notepad to see how it looks).
Pasting to the form reconstructs the component back from this text.
And as ControlCollection
property is defined in Vcl.ExtCtrls.TGridPanel
as published
, buttons within it are included in this text. Here is an excerpt:
object MyGridPanel1: TMyGridPanel
Left = 64
...
ControlCollection = <
item
Column = 0
Control = Button9
Row = 0
end
item
Column = 1
Control = Button10
Row = 0
end
...
object Button9: TButton
Left = 1
...
end
object Button10: TButton
Left = 92
...
end
...
end
When pasting, the IDE designer first creates a new object of class TMyGridPanel
. During this step the constructor of TMyGridPanel
creates a new set of buttons.
After that all published properties get reconstructed from the text, including the ControlCollection and Buttons within it, and this is where problem lies.
A possible solution in this situation is to change parent class of TMyGridPanel
to TCustomGridPanel
TMyGridPanel2 = class(TCustomGridPanel)
...
TCustomGridPanel
(similar to other TCustom...
components) does not publish any of its properties, so they won't get streamed into clipboard.
Actually inheriting from TCustom...
variants of controls, and not from the one registered in Component Pallet, is the right way to subclass components.
If we now copy this variant of TMyGridPanel2
to clipboard and paste it in notepad, we can see that there no additional properties:
object MyGridPanel21: TMyGridPanel2
Left = 184
Top = 200
Width = 185
Height = 41
end
This approach works, but have several cons that has to be noted:
You cannot access custom properties introduced by TGridPanel
in Object Inspector (but you can access them at runtime).
A workaround to bring a property back in Object Inspector, is to add it in published
section of your component:
TMyGridPanel2 = class(TCustomGridPanel)
public
...
published
property BorderStyle;
property ColumnCollection;
property RowCollection;
...
end;
You cannot change properties of the four buttons via Object Inspector, nor attach events to them. You have to do that in code.
Actually this is good behavior. When you create a composite component that has child controls, it is good practice to have all functionality contained within the component itself.
unit MyGridPanel2;
interface
uses
Classes, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Controls;
type
TMyGridPanel2 = class(TCustomGridPanel)
private
public
constructor Create(AOwner: TComponent); override;
published
end;
procedure Register;
implementation
{ TMyGridPanel2 }
constructor TMyGridPanel2.Create(AOwner: TComponent);
var
i: Integer;
btn: TButton;
begin
inherited Create(AOwner);
for i := 0 to 3 do
begin
btn := TButton.Create(Self);
btn.Parent := Self;
btn.Align := alClient;
btn.Caption := 'Hello World';
btn.Visible := True;
end;
end;
procedure Register;
begin
RegisterComponents('Custom', [TMyGridPanel2]);
end;
end.
Try this in test project first, not in production.
Upvotes: 4