Delphi在运行时重建模态表单

时间:2014-07-31 07:37:14

标签: forms delphi runtime

例如,我创建了一个小项目,以便您了解我想要实现的目标。

我有一个ModalForm,它在运行时创建了一些按钮,但是当用户按下“特殊按钮”时,我希望表单中的所有按钮都被检测到,因为其他按钮将在运行时创建。这是一个示例代码

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses Unit2;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
    button : TButton;
begin
    button := TButton.Create(Self);
    button.Parent := Form2;
    button.Caption := 'New Button';
    button.Top := 50;
    button.Left := 200;
    Form2.ShowModal;
end;

end.


unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm2 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.Button1Click(Sender: TObject);
var

button : TButton;
begin
    Form2.CloseModal;
    button := TButton.Create(Self);
    button.Parent := Form2;
    button.Caption := 'New Button';
    button.Top := 60;
    button.Left := 200;
// Form2.CloseModal;
    Form2.ShowModal;
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
      ShowModal;
end;

end.

现在在这个例子中,我在表单上有3个按钮,当我点击按钮1时,我想要第4个按钮出现。但是,如果我运行我的代码,我会收到错误

“无法制作可见的窗口模式”

我读到这与我没有正确关闭我的Form2这一事实有关。 如果我关闭Form2并单击Form1上的按钮(与Form2中的按钮相同的代码)它可以工作,我得到Form2的第4个按钮。

我现在的问题是,如何通过点击Form2中的按钮点击Form1上的按钮来获得这个结果。

2 个答案:

答案 0 :(得分:3)

这段代码有一些明显的问题。

从构造函数

调用ShowModal

表单的OnCreate事件在构造期间被触发。此时,以模态方式显示表单为时尚早。所以你不能在那里打ShowModal。我相信您应该删除TForm2.FormCreate。表单从TForm1.Button1Click以模态方式显示,这就足够了。

来自TForm2.Button1Click的CloseModalShowModal的虚假来电

无需在该方法中调用CloseModalShowModal。你可以很好地从该方法创建一个新按钮,并且不需要干扰模态循环。这是您的错误消息的原因。删除这些电话。

使用全局变量Form2而不是Self

虽然您的表单显然是单个实例表单,但您仍应避免使用Form2方法中的TForm2全局变量。在将来的某个时候,您可能希望有两个表单实例。或者完全删除全局变量。请记住,实例方法可以使用Self来引用实例。因此,例如,在TForm2方法中替换

button.Parent := Form2;

button.Parent := Self;

同样,在TForm2方法中,只要您感到被迫编写Form2.Foo,就要写Foo

枚举另一个容器内的控件

使用ControlCount的{​​{1}}和Controls[]属性查找容器中的所有控件。例如,如果您知道按钮的父级是表单,请在表单上使用TWinControlControlCount来查找其子级。然后,您可以通过在这些按钮上调用Controls[]来删除任何按钮。使用Free测试控件是按钮。

Controls[Index] is TButton

请注意,我们以反向索引顺序枚举控件。这个技巧避免了索引在我们修改列表时产生的问题,同时迭代它。

答案 1 :(得分:1)

您无需关闭和(重新)显示表单,以便动态添加控件。在TForm2.Button1Click方法中删除Form2.CloseModalForm2.ShowModal来电,即

procedure TForm2.Button1Click(Sender: TObject);
var button : TButton;
begin
    button := TButton.Create(Self);
    button.Parent := Self;
    button.Caption := 'New Button';
    button.Top := 50;
    button.Left := 200;
end;

应该有用。

BTW在Form2中向TForm1.Button1Click()添加按钮只是糟糕的设计,不要这样做(一种形式不应该像其他那样改变)。而是在Form2中创建一个方法来创建按钮,然后其他表单可以调用该函数。或者覆盖Form2的构造函数,以便它需要一个额外的参数来指示特殊按钮是否可见。

要删除按钮,只需在其上调用Free即可。即删除表单上的所有按钮

for x := ControlCount - 1 downto 0 do begin
   if(Controls[x] is TButton)then Controls[x].Free;
end;

但是如果您有预定义数量的按钮,最好在设计时创建它们,然后根据需要更改Visible属性。