2012-12-05 32 views
3

我使用的是Delphi 5,我在运行时创建了一些面板,然后在面板上创建按钮,显然在运行时也是如此。我需要这样做,因为我可能需要在未来动态创建更多面板/按钮组合。德尔福 - 在运行时创建的引用组件

我可以做所有这些,但是我不知道如何引用我创建的面板,因为我找不到访问面板组件名称的方法。在Internet上搜索我发现我可以使用FindComponent来按名称查找面板组件,但我仍然不知道如何使用该名称,因为我无法使用字符串变量来引用它 - 例如, StringVar:= Panel.Name。我得到一个类型不匹配,TComponentName与String。

我在创建面板时为每个面板创建了按钮。简化,它看起来像这样:

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; 

我读过几个论坛(包括这一个),没有办法通过名称直接引用面板。我试过使用组件数组,但是我遇到了同样的问题 - 我需要通过指定的组件名称来引用组件。

好的,我不是一个枪程序员 - 我用Delphi多年来创建简单的程序,但这个更复杂。我以前从未使用过运行时组件创建。

我可以使用FindComponent使面板可见或不可见吗?如果是这样,鉴于我在上面给你们展示的东西,你能给我采取婴儿步骤的方法吗?

在此先感谢...

+1

您可以将需要的组件添加到TList | Container ...然后使用您的列表容器访问它们... – Whiler

+2

这不是论坛。 :) – jachguate

回答

9

我不知道你所说的意思: “我不能使用一个字符串变量来引用它 - 比如STRINGVAR:= Panel.Name

试试这个:

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; 

还是我错过了什么?

+2

不,你没有。它应该很明显,但事实并非如此!非常感谢。 – Capfka

+0

我在其他面板内有一个面板,所以我用这种方法首先找到父面板,然后从父面板调用FindComponent函数,这是工作。谢谢。 – QMaster

6

你与变量名混为一谈的组件名称。 Delphi IDE努力使这两者保持一致,即IDE创建的组件,但它们不一定相同。您没有变量名称,因为您正在动态创建组件,并且您不知道需要多少个变量。但是,您仍然可以控制组件名称:只需指定组件的Name属性,然后通过调用FindComponent,以与使用其他组件名称相同的方式使用它。只要确保每个面板实例的名称都是唯一的。

还要记住的方式来处理变量,当你不知道在编译时你需要多少,是用阵列名单。您可以使用普通的旧数组,或者您可以使用更复杂的数据结构,如TComponentListTDictionary

最后,为了更容易地指的是你要创建的面板上的控制,你可以用面板分配和使用来代替。您可以在IDE中直观地设计一个TFrame并为按钮命名,并且在运行时,可以实例化框架类,并且它会自动为您创建所有按钮,就像实例化表单或数据模块时一样。您只需要为新的框架对象命名,但该对象已经具有指向按钮的命名字段。

+0

+1; TDictionary已经可以在D5上使用了吗? – Whiler

+1

@Whiler,不,但我们并不需要针对每个可能的Delphi版本单独提出问题和答案。不管版本如何,这都是同样的问题。人们可以在他们阅读这个答案时使用的版本中使用他们可以使用的任何类。此外,我没有说它必然是现代Delphi版本中的'TDictionary'类;任何人都可以编写一个类似字典的类并使用它来存储对象引用。 –

+0

thx的解释;) – Whiler

0

您可以将需要的组件添加到TList | Container ...然后,用你的列表|容器来访问它们

var 
    slPanels: TStringList; 
... 


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; 
     slPanels.AddObject(FieldByName('PanelName').AsString, pnl); 

当你需要它:

TPanel(slPanels.Objects[slPanels.IndexOf(FieldByName('PanelName').AsString)]) ... 

我不喜欢上面的代码(有更好的容器......但是这应该做的工作: o))

+2

为什么每个人都坚持创建一个单独的列表?该表单已经有一个(在Components数组中),也许有两个(Controls数组),父级有一个或两个(在Components和Controls数组中)。你不需要另一个。如果您需要将它们分组,请使用命名约定或为“标签”属性设置一个值。 –

+0

也许是因为我可以用字符串而不是整数来访问它? ; o) – Whiler

+0

当然...你的方式去做,节省内存......(你有影响delphi研发实现TagString属性与FMX?))) – Whiler

1

应该不需要创建您创建的项目的辅助列表以显示在tForm实例上。

据我所知,只要您创建一个使用窗体或地方自

pnl := Tpanel.Create(Self); 

的其他容器,你不需要采取销毁,然后新PNL的照顾,因为它是由处理的新面板包含“自我”组件。

这意味着应该有任何将持有父组件的子组件的构造。

我希望你会在父对象中找到ComponentCount或Components列表或FindComponent方法。 假设“自我”引用的对象是一个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) ; 

将更改应用程序中tPanel的所有标题。 为了区分由代码和设计器创建的面板,您可以使用每个创建的tPanel的TAG属性并在上例中使用它。

+0

是的,谢谢,我一直在使用标签来保持面板的“顺序”,方法是根据数据表的特征将数据分配给它们。 – Capfka