2010-02-01 92 views
5

我偶然在這頁Why shouldn’t I call Application​.CreateForm。 現在我有一些像這樣的代碼:如何避免兩次調用Application .CreateForm?

SplashForm := TSplashForm.Create(Application); 
SplashForm.Show; 
SplashForm.Update; // force update 
Application.Initialize; 
Application.CreateForm(TClientData, ClientData); 
SplashForm.Update; // force update 
Application.CreateForm(TClientMainForm, ClientMainForm); 
Application.ShowHint := True; 

Application.Run; 
ClientMainForm.ServerConnected := false; 
FreeAndNil(ClientMainForm); 
FreeAndNil(ClientData); 

首先創建一個splashform,然後一個數據模塊和持續的主要形式。該頁面說Application.CreateForm不應該被調用兩次。上面的代碼應該改變嗎?

Regards

回答

5

多次使用Application.CreateForm沒有任何問題。但是這爲每個可能是代碼味道的表單引入了全局變量。 不幸的是,IDE爲每個表單創建一個。雖然你可以刪除它們,如果你喜歡。

更好的方法是在需要時創建表單,並在您準備好時釋放它。所以你只使用Application.CreateForm作爲主窗體。

主要的數據模塊可以通過主窗體創建。但它也可能是全球性的,僅僅是品味的問題。

所以要回答這個問題,可以通過在本地創建和釋放表單來避免Application.CreateForm。

該文章提到了Application.CreateForm的副作用(第一個完成的表單是主窗體)。 因此,如果主窗體使用Application.CreateForm創建其他窗體,可能會出現意想不到的副作用。

所以,爲了避免任何噁心,你應該限制你的唯一的呼叫。這隻用一個全局表單來完成。

+0

我不認爲這是更好的風格去除IDE中創建全局。這些是Delphi應用程序工作的一部分。實際上,這種「優化」更像是一種「代碼異味」,而不是非優化的IDE生成的代碼。 – 2010-02-01 15:21:59

+4

@Warren:這個評論根本沒有任何意義。除了主窗體變量以外,Delphi應用程序不需要使用這些全局變量中的*任何*,並且主窗體中的一個可以很容易地被項目文件中的一個變量所替代,這個變量不會被知道任何其他單位,所以它也不會是一個真正的全球變量。 – mghie 2010-02-01 17:38:59

+0

我只是在評論「雖然你可以刪除它們,如果你喜歡」這句話,我不認爲這是一個好主意。 – 2010-02-01 19:38:24

1

如果TClientData是一個數據模塊,並且TClientMainForm是一個表單,那麼no(除了可能在最後的兩個FreeAndNil調用 - 不是真的需要)。但保重。因爲它羅布·肯尼迪說,在他的帖子中,Application.CreateForm確實落後於其他東西(它設置的MainForm變量),所以我會建議建立按以下規則項目文件:

  1. 使用單一調用創建所有想要在啓動時創建的表單至Application.CreateForm - 通常這由IDE完成。

  2. 從項目文件中刪除您要在程序中動態創建(按需)的表單。 (在Project |選項|表格...) - 從「自動創建窗體」將它們移到「可用」

  3. 創建窗體中使用TmyForm.Create(所有者)你代碼(等)和不是Application.CreateForm(...)。順便說一句,如果你確信你會釋放表格,那麼最好(爲了加快速度)撥打TmyForm.Create( - 低於沒有任何所有者。

  4. 如果你想在啓動時做一些初始化的,你可以在綁已創建的窗體/數據模塊的項目文件中的程序/方法和之前運行的應用程序運行它。

例如:

begin 
    Application.Initialize; 
    Application.MainFormOnTaskbar := True; 
    Application.CreateForm(TdmoMain, dmoMain); //<--this is a data module 
    Application.CreateForm(TfrmMain, frmMain); //<--this will became the main form 
    Application.CreateForm(TfrmAbout, frmAbout); 
    //... other forms created here... 
    frmMain.InitEngine; //<--initialization code. You can put somewhere else, according with your app architecture 
    Application.Run; 
end. 

通過這種方式,您將有項目文件乾淨,你會確切地知道哪個是哪個。

HTH

+0

+1 PLAINTH的答案解釋並遵循了大多數Delphi開發人員使用的既定約定。除此之外的任何事情都違反了我所說的「最小驚奇原則」。 – 2010-02-01 15:23:39

1

當我寫這篇文章,我想主要的代碼的DPR文件。人們可以在DPR文件中看到由IDE生成的表單創建代碼,並認爲這是創建表單的最佳方式,所以他們在程序中的其他地方使用。他們有時在主窗體的OnCreate事件處理程序中使用它來創建其程序所需的其他窗體,然後他們遇到了問題,因爲該程序的主窗體並非他們的想法。

在您提供的代碼中,只需調用一次CreateForm就很容易。用它作爲主窗體,除此之外別無它用。數據模塊不是主要的形式,所以你不需要CreateForm的魔力。

SplashForm := TSplashForm.Create(Application); 
SplashForm.Show; 
SplashForm.Update; // force update 
Application.Initialize; 

// Change to this. 
ClientData := TClientData.Create(Application); 

SplashForm.Update; // force update 
Application.CreateForm(TClientMainForm, ClientMainForm); 
Application.ShowHint := True; 

Application.Run; 
ClientMainForm.ServerConnected := false; 

// Remove these. 
FreeAndNil(ClientMainForm); 
FreeAndNil(ClientData); 

你真的不應該釋放你在這裏創建的對象,因爲你不擁有它們。它們由全局應用程序對象擁有,因此讓它解決它們的問題:刪除兩個對FreeAndNil的調用。

+0

如果你知道主窗體已經創建好了,那麼另一個窗體就不能奇蹟般地變成主窗體。如果這個警告被理解了,那麼從當前位置以外的地方調用Application.CreateForm是個不錯的主意,當且僅當您打算讓Application對象從此時開始管理表單的生存期。然而,正如我們許多人希望只要應用程序存在並隨後被釋放的形式一樣,這就是調用Application.CreateForm所需的行爲。我稱之爲「遲到創作」,我一直都在使用它。 – 2010-02-01 19:40:12

+1

主窗體在*指定爲主窗體之前可以運行它自己的代碼。這就是問題發生的地方。如果你希望Application對象管理生命期,那麼當你調用一個表單的構造函數時,就像創建任何其他對象時一樣,只需將它指定爲Owner參數,就像我在答案中的代碼中演示的一樣。爲什麼特別重視創建表單,而實際上它與創建任何其他類的實例相同?調用CreateForm的唯一原因是您需要使用Application.MainForm進行設置。 – 2010-02-01 20:37:54

0

您引用的文章不正確。有幾個有效的原因,你爲什麼要多次調用Application.CreateForm

1)數據模塊:你可能希望所有的時間都可用。最好的方法是Application.CreateForm。我知道有幾個主題數據模塊的應用,例如客戶,發票,地址來處理數據庫的不同區域&整齊地封裝了功能。所有這些都創建在.dpr

2)大,緩慢加載的東西(這是一個壞主意在&本身,但這些事情發生,並經常由支持程序員繼承...)。將加載時間移動到應用程序啓動中,就像您的示例代碼以及啓動畫面更新一樣。用戶期望應用程序需要一段時間才能得到持續感謝我們的同事上的Microsoft Office工作的斯特林努力降低預期我們其餘的人:)

所以吧,總之,不擔心你的代碼很好 - 但你可能會失去「FreeAndNil」的東西。但是小靈通打對話框類型的東西是最好的調用:

with TMyform.Create(nil) do 
try 
    //Setup 
    case ShowModal of 
    // Whatever return values you care about (if any) 
    end; 
finally 
    Free; 
end; 

短,甜,給點&最大限度地減少內存使用...

+0

您聲稱鏈接的文章不正確,實際上是非常不正確的。你給出的*原因數量都不是你想要調用'Application.CreateForm()'的原因。 Re 1)你可以簡單地'Create()',傳遞任何'Owner'包括'Application'。 Re 2)你可以在主窗體的OnCreate事件中做第一件事,沒有人會看到任何不同之處。 – mghie 2010-02-16 08:49:01

+1

您可以用不同的方式創建表單,但是您描述的方式涉及您必須編寫額外的代碼才能獲得明顯的收益。你爲什麼要故意用「非德爾菲」的方式做事?如果您在IDE中創建表單或Datamodule,Delphi可以幫助您在運行時使用它放入.dpr中的Application.Createform語句來創建它。在與德爾福合作的16年中,我還沒有看到任何證據表明Application.Createform本質上是低效的或不適用於應用程序生命週期所需的表單,這似乎是作者的斷言。 – mcottle 2010-02-16 09:44:42