天天看點

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 forms are 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;      

繼續閱讀