如何引用在运行时而不是在表单设计器中创建的组件?

时间:2011-12-17 19:56:12

标签: delphi delphi-7

我有点问题。我正在尝试在Delphi7中创建一个运行时组件列表,并使用表单的.OnResize事件调整它们的大小但没有用...我无法弄清楚如何做到这一点。

这是我的代码:

procedure TForm1.Button1Click(Sender: TObject);
var
  //ExtCtrls
  panel: TPanel;
  memo: TMemo;
  splitter: TSplitter;
  list: TListBox;
begin
  panel := TPanel.Create(Self);
  list := TListBox.Create(Self);
  splitter := TSplitter.Create(Self);
  memo := TMemo.Create(Self);

  with panel do
  begin
    Parent := Form1;
    BevelOuter := bvNone;
    Top := 12;
    Left := 12;
    Height := Form1.Clientheight - 24;
    Width := Form1.Clientwidth - 24;
  end;

  with list do
  begin
    Parent := panel;
    Align := alClient;
    Top := 0;
    Height := panel.Height;
  end;

  with splitter do
  begin
    Parent := panel;
    Top := 0;
    Width := 12;
    Align := alLeft;
  end;

  with memo do
  begin
    Parent := panel;
    Top := 0;
    Left := 0;
    Width := round(panel.Width / 4) * 3;
    Height := panel.Height;
    Align := alLeft;
  end;
end;

我是否必须以某种方式注册他们的名字才能在表单的活动中使用它们?或者,也许,创建一个类并包含它们?

非常感谢任何形式的帮助!提前谢谢。

3 个答案:

答案 0 :(得分:9)

您的变量是创建它们的过程的本地变量,因此当您在该过程之外时,您无法使用这些变量来引用它们。解决方案是使它们成为表单类的字段。

type
  TForm1 = class(TForm)
    procedure FormResize(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    FPanel: TPanel;
    FMemo: TMemo;
    FSplitter: TSplitter;
    FList: TListBox;
  end;

然后您的FormResize事件处理程序可以引用它们。

procedure TForm1.FormResize(Sender: TObject);
begin
  if Assigned(FPanel) then
  begin
    ...
  end;
end;

不要忘记从Button1Click中删除局部变量,而是使用这些字段。

procedure TForm1.Button1Click(Sender: TObject);
begin
  FPanel := TPanel.Create(Self);
  ...
end;

答案 1 :(得分:4)

尽管大卫的答案也非常正确,但我想我会花点时间详细介绍一下。从它的外观来看,你似乎是Delphi的新手。初学者有一个非常普遍的问题,大卫在他的回答中没有提到,这与创建和释放这些对象有关。无论何时你曾经在课堂上打过'创造',在某些时候,当你完成它时,你也必须'自由'那个课。未能释放任何内容将导致内存泄漏,没有人想要这样做。解放就像创建一样简单 - 直到你进入保持对象列表(你现在不需要)的主题。

假设您要创建一个文本框(TEdit)控件并将其放在表单的中心。首先,Delphi IDE允许您简单地将这些控件放在表单中,只需确保您知道。除非有一些特殊情况,否则您不一定需要自己创建/释放它们。但这样做很危险。为了这个例子,我们假设这个TEdit控件将在整个应用程序期间存在。

首先,您需要为此控件声明某个变量。最合理的地方是在将要使用它的类中(在这种情况下,我们称之为Form1的表单)。在表单中使用变量(也称为字段)时,请确保不要在private部分之外放置任何内容。高于private的所有内容都是由Delphi自动生成的代码,用于表单中已删除(并且是可视)的任何内容。否则,任何手动创建的内容都必须位于privatepublic下。 public区域将是您控制的好地方......

type
  TForm1 = class(TForm)
  private

  public
    MyEdit: TEdit;
  end;

现在宣布它,我们必须创建(和免费)它。这是一个很好的做法,任何时候你创造的东西,你立即把代码放在你继续工作之前释放它。为表单的OnCreateOnDestroy事件制作事件处理程序...

procedure TForm1.FormCreate(Sender: TObject);
begin
  MyEdit:= TMyEdit.Create(nil);
  MyEdit.Parent:= Self;
  MyEdit.Left:= (ClientWidth div 2) - (Width div 2);
  MyEdit.Top:= (ClientHeight div 2) - (Height div 2);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if assigned(MyEdit) then MyEdit.Free;
end;

如果未创建此对象(在创建之前或销毁之后),则在尝试使用它时将出现“访问冲突”。这是因为您的应用程序试图访问未分配的计算机内存区域或与您要获取的类型不匹配。

嗯,这是修复场景的基础知识。然而,还有一件事要告诉你。假设您需要在过程的持续时间内短时间创建一个对象。这有不同的方法。在上面的代码中,您直接在过程中声明了变量。此示例将向您显示何时需要执行此操作...

procedure TForm1.Button1Click(Sender: TObject);
var
  MyObject: TMyObject;
begin
  MyObject:= TMyObject.Create;
  try
    MyObject.DoSomething;
    Caption:= MyObject.GetSomething;
  finally
    MyObject.Free;
  end;
end;

你知道,只要MyObject只用于这个程序的调用,你就可以在这里声明它。但是,如果在完成此过程并且完成此过程后,预期对象将保留在内存中,则事情变得更加复杂。同样,在你的情况下,坚持把它放在表格的类中,直到你更熟悉动态创建对象。

最后一点,如上所述,您可以在设计时直接将TEdit控件放在表单上,​​而无需编写自己的代码。如果你这样做,你需要记住不要尝试创建或释放这些。当Delphi自动将代码置于private部分之上时,就会出现这种情况 - 当有些东西你不应该玩的时候。

答案 2 :(得分:2)

我认为我没有资格“评论”,所以我将其称为“答案”。如果要在父级更改大小时调整运行时组件的大小,请仔细查看Anchors属性。它可以为您节省大量的工作。