Delphi MDI多文件架構幾個問題解決
1.關於登入視窗(Login):
很多時候我們在做開發delphi的MDIform時,常常因為要做進去Login一個正常的登入視窗,平常做Login的project程式碼如下:
只有Login登入成功了時候,才會建立起frm_Main窗體,這是正常不用MDI框架的正常登入與主窗體切換。
Application.CreateForm(Tfrm_Login, frm_Login); if frm_Login.ShowModal = mrOK then //登入窗體關閉時返回了mrOK值,說明登入成功 begin Application.CreateForm(Tfrm_Main, frm_Main); frm_Main.ShowModal;end;
現在問題是frm_Main是MDI主窗體,而delphi會把第一個CreateForm認定為MDI主窗體,而frm_Login的FormsTyle是fsNormal正常窗體。
如果按上面的程式碼的話,將導致“Cannot create form.No MDI formsare currently active."
解決方案:
既然delphi會把第一個CreateForm認定為MDI主窗體,那我們就把Application.CreateForm(Tfrm_Main,frm_Main);放在最前,project程式碼如下:
Application.CreateForm(Tfrm_Main, frm_Main); Application.CreateForm(Tfrm_Login, frm_Login);
這樣的話執行後的第一個視窗不是Login 而是Main窗體,這時我們需要再Main窗體OnCreate事件中加進如下程式碼:
procedure Tfrm_Main.FormCreate(Sender: TObject); begin with Tfrm_Login.Create(Self) do ShowModal; end;
加上這句後的,執行後的第一個視窗就是Login,第一個問題解決。
2.關於MDI子窗體最小化,與窗體恢復:
在做MDI窗體的時候,點選選單按鈕撥出第一個MDI子窗體。對MDI子窗體最小化後,我們會看到窗體在主窗體的左下角。
而當我們往往再次點選選單那個按鈕不是再次重新建立一個窗體,而是對原有窗體進行撥出選擇並顯示。(比如MDI子窗體最小化了,而我們點選選單該子窗體按鈕時,該子窗體應重新Restrore到中央)
一開始,我試著對frm_UserDefine(我的一個MDI子窗體)進行控制。包括以下:
showwindow(frm_UserDefine.handle, sw_restore); // 顯示子視窗
SendMessage(frm_UserDefine.Handle,MY_SETSTATE_MSG,0,0);// 傳送訊息到子視窗 觸發訊息進行Restore
都不管用,甚至以下程式碼,都會報記憶體錯誤
procedure Tfrm_Main.N9Click(Sender: TObject); var frm_UserDefine: Tfrm_UserDefine; begin if not isInclude(Tfrm_UserDefine) then begin frm_UserDefine := Tfrm_UserDefine.Create(Application); frm_UserDefine.Show; end else begin frm_UserDefine.Show; end; end;
當重新點選時 判斷了frm_UserDefine已建立,重新show時就報錯,最後跟蹤查了下frm_UserDefine找不到,我也不太清楚什麼原因。
解決方案:
我在判斷子窗體是否存在時,若存在就對其進行Restore,就把這個功能實現了,程式碼如下:
function Tfrm_Main.isInclude(Formclass: TFormClass): Boolean; var i: Integer; Form: TObject; begin Result := false; for i := 0 to frm_Main.MDIChildCount do begin Form := frm_Main.MDIChildren[i]; if Form is Formclass then begin Result := true; SendMessage(MDIChildren[i].Handle, WM_SYSCOMMAND, SC_RESTORE, 0); //在這裡對MDI視窗進行管理恢復 MDIChildren[i].Enabled:=true; MDIChildren[i].Show; MDIChildren[i].SetFocus; end; end; end;
procedure Tfrm_Main.N9Click(Sender: TObject); var frm_UserDefine: Tfrm_UserDefine; begin if not isInclude(Tfrm_UserDefine) then begin frm_UserDefine := Tfrm_UserDefine.Create(Application); frm_UserDefine.Show; end; end;
這樣就實現了重新點選就能使子窗體重新恢復的功能。不過大家有什麼更好的解決方法也可以跟我留言。
3.關於MDI子窗體被主窗體控制元件遮擋問題
因為要在主窗體插入Falsh或者Webbrower控制元件,panel控制元件做總體導航時,因為MDI子窗體擋在後面而頭疼。(Image控制元件剛好沒有遮擋MDI子窗體,所以一般開發就是在MDI主窗體背後放個Image做背景),OK,現在問題是如何解決主窗體的控制元件不遮擋MDI子窗體,而且躲在底層還能點選。
解決方案:
這裡我是把子窗體的父類指向MDI主窗體,程式碼如下:
procedure Tfrm_Main.N9Click(Sender: TObject); var frm_UserDefine: Tfrm_UserDefine; begin if not isInclude(Tfrm_UserDefine) then begin frm_UserDefine := Tfrm_UserDefine.Create(Application); Winapi.Windows.SetParent(frm_UserDefine.Handle,frm_Main.Handle); frm_UserDefine.Show; end; end;
這時撥出來的 子窗體介面就在控制元件前面了,還有個小Bug,就是對子窗體最小化後看不到子窗體,這時關閉窗體會報記憶體錯誤。
其實最小化後是隱藏起來,滑鼠還是可以點選到的。(這裡怎麼會隱藏起來,可能還需要研究,如果大神知道原因的話,可以留言告訴我,我覺得可能改變了框架導致MDI錯亂了吧)
這裡可以在子窗體在最小化時show一下,且子窗體需要有控制元件(例如:panel)存在(沒控制元件存在的form也會最小化隱藏),以下為子窗體程式碼
procedure Tfrm_UserDefine.FormCanResize(Sender: TObject; var NewWidth, NewHeight: Integer; var Resize: Boolean); begin case WindowState of wsMinimized: Self.Show; end; end;
問題解決!
以上程式碼是泡泡航在Delphi XE5的開發,雖然微軟說明多文件介面MDI存在問題,但是現在以MDI窗體作為系統開發的還是蠻多的。如果大家有什麼更好的辦法或者建議,可以多多留言交流。