在Delphi 中用程序实现自定义窗体的创建和显示顺序(2)

类别:Delphi 点击:0 评论:0 推荐:

在Delphi 中用程序实现自定义窗体的创建和显示顺序(2)

 

 

 

 

以上方法虽然可以实现动态的有选择地创建和显示窗体,但是有一个致命的弱点,就是程序关闭权限的转移,不能保留Form1的程序关闭权限。怎样真正实现有选择的创建和显示窗体,并且能保持Form1为主窗体呢?方法如下:

把3个窗体都放置在Auto-create forms里面,即3个窗体都自动创建。

在Form1中设置一个全局变量

var

  flag:Integer;

 

然后把上面Form1那段代码改成如下所示:

procedure TForm1.FormCreate(Sender: TObject);

var

  randomnum:Integer;

begin

  flag:=0;

  Label1.Caption:='Form1 Create Complete!';

  Randomize;

  randomnum:=Random(10);

  if (randomnum>0)and (randomnum<=4) then

    flag:=2

  else if (randomnum>4)and (randomnum<=8) then

    flag:=3

  else

    flag:=1;

end;

   (代码6)

然后,在Form2的OnCreate() 事件中加入以下代码:

procedure TForm2.FormCreate(Sender: TObject);

begin

  Label1.Caption:='Form2 Create Completed!';

end;

在Form3的OnCreate() 事件中加入以下代码:

procedure TForm3.FormCreate(Sender: TObject);

begin

  Label1.Caption:='Form3 Create Complete!  (' +IntToStr(flag)+')  ';

  Form3.Hide;

  if flag=3 then

  Begin

    Form3.Visible:=True;

  End

  else if flag=2 then

  Begin

    Form2.Visible:=true;

  End

  else if flag=1 then

  Begin

    Form1.Show;

 end;

   (代码7)

还要记得把Form2和Form3的FormStyle属性改成fsStayOnTop,把Form1的FormStyle属性设成fsNormal,否则无法在屏幕的最前端显示所需要的窗体。把Form2和 Form3的Visible属性设成False,否则程序将无法正确地Focus(聚焦)于所需窗体。经过这样的修改之后就能根据随机结果选择最终要显示的窗体。

分析一下上面的过程可知道,窗体1,2,3是按顺序创建的,但是在Form1的创建过程中设置了一个全局变量作为记录的标记,记录应该显示的是哪个窗体,Form2的创建过程没有做任何动作,只是简单的一个显示信息,而在Form3的创建过程中则判断标志flag的值,由此决定究竟应该显示哪个窗体。

注意到主窗体是一定会显示出来的,这也是Form1的Visible没有设置成 False的原因,因为即使设置成False,也是会显示出来的。

以上所说的方法,其中的3个窗体都是已经被完全创建的,只是其中一个或两个没显示出来而已(设置成Visible为False),如果现在打开Spy++,可以清楚地看到3个窗口都在。但是我们的目的不仅仅如此,我们还要实现窗体创建的动态性和选择性。

前面说过使用Appliation.CreateForm()的方法来动态创建窗体有它的局限性,就是所谓的权限的转移。实际上我们可以改变这种情形,方法如下:

在Project1.dpr中只创建Form1

begin

  Application.Initialize;

  Application.CreateForm(TForm1, Form1);

  Application.Run;

end.

在Form1的OnCreate()中的代码和代码5一样。Form2,Form3的OnCreate()不需要任何代码, 这时程序的关闭权限还是没有回到Form1的手里,其实我们只要在Form1的OnClose()中加入一句就行了:

  Application.Terminate;

如果不加入这一句,则关闭Form1是不会关闭整个应用程序的,必须关闭Form2或Form3才行。 有些人可能会问,为什么不是Free而是Terminate呢?查一下Delphi的帮助文件关于Free的描述,其中有一个注意事项如下所述:

Warning: Never explicitly free a component within one of its own event handlers or the event handler of a component it owns or contains. For example, don’t free a button, or the form that owns the button, in its OnClick event handler.

可以看到,在Delphi中不能在一个组件它自己的事件处理中明确地释放这个组件。这就是为什么不能用Application.Free的原因。必须用Application.Terminate这一句来释放窗体创建的资源,否则将出现资源没有释放的错误。如何知道资源没有释放呢?在Delphi编译器则体现为Project在Running状态,并且需要通过Run->Program Reset来结束程序;另外,如果把程序Build了之后,脱离Delphi编译器直接运行程序,然后关闭Form1,这时候打开Windows的任务管理器,在进程一页将显示Project仍然在,占用着内存和CPU,需要通过结束进程来去掉它。

关于Application.Terminate,Delphi的帮助文件有这样的描述:

Call Terminate to end the application programmatically. By calling Terminate rather than freeing the application object, you allow the application to shut down in an orderly fashion.

这里,Delphi很明确的告诉我们,调用Terminate而不是Free,可以让应用程序以整齐的方式关闭。

到这里我们的任务还没结束,我们只是让Form1 和Form2或者是Form3有同等的关闭程序的权限,我们还要剥夺Form2或是Form3的程序关闭权,方法是在Form2和Form3的OnClose()事件函数中加入一句Application.Run,这样按Form2和Fomr3的关闭按钮都不会有什么反应了,当然也就不会关闭程序了。我们再添加一个按钮用来“关闭”窗体,在其Onclik事件中加入一句

Form2.Visible:=False;

所谓的关闭其实是把显示关闭,而不是把窗体关闭,窗体的资源是没有释放的。Delphi的帮助文件中关于Application.Run的描述不鼓励我们使用Run,但是从实际使用情况来看,并没有什么坏处,只是窗体的关闭按钮的功能被屏蔽掉了,但是我们有替代的办法,把窗体的BorderStyle属性设置成bsNone就可以把窗体的Title标题栏取掉,用其他按钮或者其他控件,代替标题栏上的最小化,最大化,关闭按钮。

到此为止,我们可以说是基本解决了本文开始提出的问题,但是还有一个重要问题我们忽略了,Fom1总是会出现,聪明的你可能想到了在Project.dpr中编写一些代码来处理,对极了,请看下面代码:

program Project1;

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, StdCtrls,

  Unit1 in 'Unit1.pas' {Form1},

  Unit2 in 'Unit2.pas' {Form2},

  Unit3 in 'Unit3.pas' {Form3};

 

{$R *.res}

var

  randomnum:Integer;

begin

  Application.Initialize;

  Randomize;//设置随机器

  randomnum:=Random(10);//在0到10之间取随机值

  if (randomnum>0)and (randomnum<=4)then//如果随机值在0到4之间

  Begin

    Application.CreateForm(TForm2, Form2);

  End

  else if (randomnum>4)and (randomnum<=8)then//如果随机数在4到8之间

  Begin

    Application.CreateForm(TForm3, Form3);

  End

  Else     //如果随机数在8到10之间

  Begin

    Application.CreateForm(TForm1, Form1);

  End;

  Application.Run;

end.

实现以上代码后,Form1,Form2,Form3不用写任何处理代码,不用修改任何属性,就能解决我们的问题,我们可能要慨叹了,为什么一开始没想到这样做。

 

三.  总结

使用Appliation.CreateForm()的方法来动态创建窗体有它的局限性,本文介绍了一个简单而实用的方法用来动态显示窗体,这种方法的关键是设置一个标志,根据实际情况给标志赋值,等到全部窗体创建完毕后,根据所设标志决定需要显示的窗体。但是这种方法的缺点是所有的窗体都将被创建。本文介绍了另外一种方法,这种方法能真正实现动态选择创建窗体,但是同样存在缺点,就是程序关闭权限被平均化了,但是我们有相应的解决办法。这两种方法各有其优缺点,为此我们用到第三种方法,在Project.dpr中编写代码实现窗体的动态选择创建,到此则完满地解决了本文开始提出的问题。

如果读者有更好的建议或解决办法,欢迎指教,我的Email是[email protected].

 

 

本文地址:http://com.8s8s.com/it/it5302.htm