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窗体作为系统开发的还是蛮多的。如果大家有什么更好的办法或者建议,可以多多留言交流。