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;

问题解决!

以上代码是泡泡航在Delphi XE5的开发,虽然微软说明多文档界面MDI存在问题,但是现在以MDI窗体作为系统开发的还是蛮多的。如果大家有什么更好的办法或者建议,可以多多留言交流。

原文地址:https://www.cnblogs.com/jijm123/p/13804089.html