Delphi MDI多文档架构几个问题解决

摘要:
1.关于登录窗口:很多时候我们在做开发delphi的MDIform时,常常因为要做进去Login一个正常的登录窗口,平常做Login的project代码如下:只有Login登录成功了时候,才会建立起frm_Main窗体,这是正常不用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值,说明登录成功
    beginApplication.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事件中加进如下代码:

procedureTfrm_Main.FormCreate(Sender: TObject);
begin
  with Tfrm_Login.Create(Self) doShowModal;
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

都不管用,甚至以下代码,都会报内存错误

procedureTfrm_Main.N9Click(Sender: TObject);
varfrm_UserDefine: Tfrm_UserDefine;
begin
  if not isInclude(Tfrm_UserDefine) then
  beginfrm_UserDefine := Tfrm_UserDefine.Create(Application);
    frm_UserDefine.Show;
  end
  else
  beginfrm_UserDefine.Show;
  end;
end;

当重新点击时 判断了frm_UserDefine已建立,重新show时就报错,最后跟踪查了下frm_UserDefine找不到,我也不太清楚什么原因。

解决方案:

我在判断子窗体是否存在时,若存在就对其进行Restore,就把这个功能实现了,代码如下:

functionTfrm_Main.isInclude(Formclass: TFormClass): Boolean;
vari: Integer;
  Form: TObject;
beginResult :=false;
  for i := 0 to frm_Main.MDIChildCount do
  beginForm :=frm_Main.MDIChildren[i];
    if Form is Formclass then
    beginResult :=true;
      SendMessage(MDIChildren[i].Handle, WM_SYSCOMMAND, SC_RESTORE, 0); //在这里对MDI窗口进行管理恢复
      MDIChildren[i].Enabled:=true;
      MDIChildren[i].Show;
      MDIChildren[i].SetFocus;
    end;
  end;
end;
procedureTfrm_Main.N9Click(Sender: TObject);
varfrm_UserDefine: Tfrm_UserDefine;
begin
  if not isInclude(Tfrm_UserDefine) then
  beginfrm_UserDefine := Tfrm_UserDefine.Create(Application);
    frm_UserDefine.Show;
  end;
end;

这样就实现了重新点击就能使子窗体重新恢复的功能。不过大家有什么更好的解决方法也可以跟我留言。

3.关于MDI子窗体被主窗体控件遮挡问题

因为要在主窗体插入Falsh或者Webbrower控件,panel控件做总体导航时,因为MDI子窗体挡在后面而头疼。(Image控件刚好没有遮挡MDI子窗体,所以一般开发就是在MDI主窗体背后放个Image做背景),OK,现在问题是如何解决主窗体的控件不遮挡MDI子窗体,而且躲在底层还能点击。

解决方案:

这里我是把子窗体的父类指向MDI主窗体,代码如下:

procedureTfrm_Main.N9Click(Sender: TObject);
varfrm_UserDefine: Tfrm_UserDefine;
begin
  if not isInclude(Tfrm_UserDefine) then
  beginfrm_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; varNewWidth,
  NewHeight: Integer; varResize: Boolean);
begin
  case WindowState ofwsMinimized: Self.Show;
  end;
end;

问题解决!

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

免责声明:文章转载自《Delphi MDI多文档架构几个问题解决》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇JimuReport积木报表 — API数据源报表带参制作Jenkins构建、推送、拉取镜像和发布应用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

DEV控件

1、问题:为什么从A窗体中拷贝的控件到B窗体中不能用? 答:这是由于拷贝的控件在A窗体中已经声明了引用,所以在拷贝的时候没有拷贝该控件的声明,在B窗体中没有声明,所以不能用。 2、问题:给DEV控件的RibbonPage添加图片绑定,怎么区分? 答:RibbonPage中有IMage属性和LargeImage属性,第一个是绑定小图片,第二个是绑定大图片,一...

DotNetBar教程

DotNetBar是一组用于.NET Framework环境下的一组组件集,利用该组件集能够打造绚丽并且实用的应用程序界面,给开发人员提供极大的便利。关于DotNetBar,详情请参考其官方网站:http://www.devcomponents.com 该组件集目前最新版本是8.8(不知最近有没有升级版本),可以从该网站上下载到试用期为一个月的试用版本。...

Delphi 实现窗体自适应调整尺寸以适应不同屏幕分辩率的显示问题

给你一段代码,网上转的:unit uMyClassHelpers;//实现窗体自适应调整尺寸以适应不同屏幕分辩率的显示问题。//        陈小斌,2012年3月5日interfaceUses  SysUtils,Windows,Classes,Graphics, Controls,Forms,Dialogs, Math,typinfo;//  uMy...

安装UniDAC控件包

UniDAC是一个功能强大的非可视化跨数据库的数据访问组件,可用于Delphi,Delphi for .NET,C++Builder,and Lazarus (Free Pascal)。它提供了对流行数据库服务器的统一访问,像Oracle,Microsoft SQL Server,MySQL,InterBase,Firebird,PostgreSQL,SQ...

WinForm窗体自适应分辨率

我们自己编写程序的界面,会遇到各种屏幕分辨率,只有自适应才能显的美观。实际上,做到这点也很简单,就是首先记录窗体和它上面控件的初始位置和大小,当窗体改变比例时,其控件的位置和大小也按此比例变化即可。因为窗体上控件的位置和大小是相对于自己所在的窗体的,也就是所谓的窗口坐标。     在这里我们只考虑相对于自己窗体的窗口坐标更简单,也就是成比例变化。为了多个窗...

C#——获取鼠标当前坐标

Control.PointToScreen:将指定工作区点的位置计算成屏幕坐标 Control.MousePosition:  鼠标相对于屏左上角的坐; this.PointToClient(Control.MousePosition): 将指定屏幕点的位置计算成工作区坐标 (鼠标相对于窗体工作区的坐标); this.Location:窗体左上角相对于屏左...