Referencing Components created at Runtime
I'm using Delphi 5 and I'm creating a number of panels at runtime, then creating buttons on the panels, obviously again at runtime. I need to do it this way because I may need to dynamically create more panel/button combinations in the future.
I can do all of this, but I'm at a loss as to how to reference the panels I've created, because I can't find a way to access the panels' component name. Hunting around the Internet I've found that I can use FindComponent to find the panel components by name, but I still don't know how to use that name, because I can't use a string variable to refer to it - eg StringVar := Panel.Name. I get a type mismatch, TComponentName versus String.
I created the buttons for each panel as I created the panels. Simplified, it looks like this:
With TypeQuery do begin // Create Panels
First;
While (not eof) do begin // create the actual panel
panelno := FieldByName('Product_type_id').AsInteger;
pnl := Tpanel.Create(Self);
pnl.name := FieldByName('PanelName').AsString;
pnl.color := clInactiveCaption;
pnl.parent := MainForm;
pnl.width := 365;
pnl.Height := 551;
pnl.left := 434
pnl.top := 122;
pnl.caption := '';
With ButtonQuery do begin
Close;
Parameters.parambyname('PanelID').Value := PanelNo;
Open;
First;
While (not eof) and (FieldByName('Product_type_id').AsInteger = PanelNo) do begin //put the buttons on it.
btnName := FieldByName('ButtonName').AsString;
BtnText := FieldByName('ButtonText').AsString;
BtnGroup := FieldByName('Product_Group_ID').AsString;
GrpColour := FieldByName('ButtonColour').AsString;
btn := TColorButton.Create(Self);
btn.Parent := pnl;
btn.Name := BtnName;
Btn.backcolor := HexToTColor(GrpColour);
btn.Font.Name := 'Arial Narrow';
btn.Font.Style := [fsBold];
btn.Font.Size := 10;
. . .
end;
. . .
end;
end;
I've read on several forums (including this one) that there is no way to reference the panels by name directly. I've tried using a component array, but I strike the same problem - I need to refer to the component by its assigned component name.
Okay, I'm not a gun programmer - I've used Delphi for years to create simple programs, but this one is a lot more complex. I've never worked with runtime component creation before.
Can I use FindComponent to make the panels visible or invisible? If so, given what I have shown you above, can you give me the approach I should take in baby-steps?
Thanks in advance ...
I'm not sure what you mean by: "I can't use a string variable to refer to it - eg StringVar := Panel.Name."
Try this:
procedure TForm1.FormCreate(Sender: TObject);
var
p: TPanel;
begin
p := TPanel.Create(Self); // create a TPanel at run-time
p.Name := 'MyPanel'; // set a unique name
p.Parent := Self;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
p: TPanel;
StringVar: string;
begin
p := FindComponent('MyPanel') as TPanel;
if Assigned(p) then // p has reference to MyPanel
begin
// use that reference
p.Caption := 'Foo';
StringVar := p.Name;
ShowMessage(StringVar);
end;
end;
Or did I miss anything?
You're conflating the component name with the variable name. The Delphi IDE strives to keep those two the same, for IDE-created components, but they're not necessarily equal. You don't have variable names because you're creating the components dynamically, and you don't know how many variables you'd need. However, you still have control over the component names: Simply assign the Name
property of the component, and then you can use it the same way you use any other component names, by calling FindComponent
. Just make sure the names are unique for each panel instance.
Remember also that the way to deal with variables, when you don't know at compile time how many you'll need, is to use arrays or lists. You can use plain old arrays, or you can use a more sophisticated data structure like TComponentList
or TDictionary
.
Finally, to make it easier to refer to the controls on the panels you're creating, you can dispense with the panels and use frames instead. You can visually design a TFrame
in the IDE and give names to the buttons, and at run time, you can instantiate the frame class, and it will automatically create all the buttons for you, just like when you instantiate a form or data module. You only need to give a name to the new frame object, but that object will already have named fields referring to the buttons.
There should be no need to create a secondary list of items you created to display on a tForm instance.
AFAIK, whenever you create a new panel that uses a Form or an other Container in place of self
pnl := Tpanel.Create(Self);
you don't need to take care of destroying then new pnl, because it is handled by the containing "self" component.
This means that there should be any construct that will hold the child components of the parent component.
I expect that you will find, either a ComponentCount, or Components list or a FindComponent method in the parent object. Assuming that the "Self" referenced object is a Tform.
for i := 0 to tForm(self).ComponentCount -1 do
if tForm(self).Components[i] is tPanel then
tPanel(tForm(self).Components[i]).Caption := intToStr(i) ;
will change all Captions of tPanels in your application. In order to distinguish between Panels created by code and designer you can use the TAG property of each created tPanel and use it in the above example.
链接地址: http://www.djcxy.com/p/91072.html上一篇: 我不能在Delphi 7上安装TeeChart2013
下一篇: 引用在运行时创建的组件