1. 程式人生 > 實用技巧 >Delphi MDI多文件架構幾個問題解決

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窗體作為系統開發的還是蠻多的。如果大家有什麼更好的辦法或者建議,可以多多留言交流。