在Delphi 中用程式實現自定義窗體的建立和顯示順序(2) (轉)

gugu99發表於2007-08-16
在Delphi 中用程式實現自定義窗體的建立和顯示順序(2) (轉)[@more@]

在 中用實現自定義窗體的建立和顯示順序(2)

 

 

 

 

以上方法雖然可以實現動態的有選擇地建立和顯示窗體,但是有一個致命的弱點,就是程式關閉的轉移,不能保留Form1的程式關閉許可權。怎樣真正實現有選擇的建立和顯示窗體,並且能保持Form1為主窗體呢?方法如下::namespace prefix = o ns = "urn:schemas--com::office" />

把3個窗體都放置在Auto-create forms裡面,即3個窗體都自動建立。

在Form1中設定一個全域性變數

var

  flag:Integer;

 

然後把上面Form1那段程式碼改成如下所示:

procedure TForm1.FormCreate(Sender: T);

var

  rannum: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.H;

  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.Tenate;

如果不加入這一句,則關閉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 fothat owns the button, in its OnClick event handler.

可以看到,在Delphi中不能在一個它自己的事件處理中明確地釋放這個元件。這就是為什麼不能用Application.Free的原因。必須用Application.Terminate這一句來釋放窗體建立的資源,否則將出現資源沒有釋放的錯誤。如何知道資源沒有釋放呢?在Delphi則體現為Project在Running狀態,並且需要透過Run->Program Reset來結束程式;另外,如果把程式Build了之後,脫離Delphi編譯器直接執行程式,然後關閉Form1,這時候開啟的工作管理員,在程式一頁將顯示Project仍然在,佔用著和,需要透過結束程式來去掉它。

關於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中編寫程式碼實現窗體的動態選擇建立,到此則完滿地解決了本文開始提出的問題。

如果讀者有更好的建議或解決辦法,歡迎指教,我的E是.

 

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-960878/,如需轉載,請註明出處,否則將追究法律責任。

相關文章