本章要点
多文档界面程序的概念
多文档界面的结构
多文档界面程序的设计
多文档界面的菜单
使用多文档界面模板
Windows应用程序按其文档结构可以划分为单文档界面应用程序和多文档界面应用程序。
单文档界面(SingleDocumentInterface,SDI)应用程序,就是应用程序在同一时刻只能打开一个窗口,即只能处理一个文档,若想打开另一个文档或新建一个文档,原窗口必须关闭。如Windows中的记事本就是一个单文档界面应用程序。
多文档界面(MultipleDocumentInterface,MDI)应用程序,就是应用程序可以同时拥有多个子窗口,即能同时处理多个文档,多个窗口之间可以互相切换。如MicrosoftWord就是一个多文档应用程序。多文档界面应用程序便于各窗口之间交换数据。
本章介绍多文档界面应用程序的设计。
9.1多文档界面的结构
在多文档界面应用程序中,应用程序本身使用一个窗口,称为主窗口;打开的每个文档使用一个窗口,称为子窗口。
9.1.1主窗口
多文档界面应用程序中,只能有一个主窗口。
这个主窗口看上去和普通应用程序的主窗口没有什么区别,同样有标题栏、菜单栏、缩放边框、控制菜单和最大化、最小化按钮。不同的是,它的用户区不是用于程序的输出,而是用于子窗口的显示。
创建多文档界面应用程序主窗口的过程和创建普通主窗口基本一样,但是主窗体的FormStyle属性要设置为fsMDIForm。
9.1.2子窗口
多文档界面应用程序的子窗口看上去和普通窗口一样,不同的是它们没有菜单,它们使用主窗口的菜单。
多文档界面应用程序运行时,可以同时显示多个子窗口,但每一时刻只能有一个子窗口被激活,而且所有的子窗口都显示在主窗口的边界内,子窗口最小化后的图标也在主窗口的边界内。
创建多文档界面应用程序子窗口的过程和创建普通主窗口也基本一样,但是子窗体的FormStyle属性要设置为fsMDIChild。
9.2多文档界面应用程序的设计
9.2.1多文档界面应用程序设计举例
下面通过一个实例说明多文档界面应用程序的设计过程。
例9-1设计一个多文档界面应用程序。
(1)执行【File】→【New】→【Application】菜单命令,创建新的应用程序,新建一个默认窗体Form1,作为多文档界面应用程序的主窗体。
(2)设置主窗体的属性,如表9-1所示。
(5)在主窗体中放置MainMenu组件,启动主菜单设计器,设计主窗体的菜单,如图9-1所示。
(6)选择事件、编写事件处理代码。
按功能要求,单击主窗口的【窗口】→【新建】菜单命令,应创建子窗口。【新建】菜单命令设置Name属性值为“NWindowsNew”,选择事件OnClick,并编写事件处理代码。
MainForm单元文件的部分代码如下:
这里需要说明的是:
定义了一个变量counter,用来为子窗口计数,每创建一个子窗口,counter加1,子窗口标题编号加1;创建子窗口,要调用子窗体单元文件,所以要在文件的implementation部分加入usesunit2一句;Inc(counter)是实现counter+1的系统函数。
(7)保存单元文件unit1、unit2和项目文件project1。
(8)运行程序,结果如图9-2所示。
然后执行【窗口】→【新建】菜单命令,每执行一次,创建一个子窗口,子窗口的标题依次为MDI子窗口1、MDI子窗口2等,如图9-3所示。
分析程序运行结果可以发现,程序开始运行、执行【窗口】→【新建】菜单命令之前就已经创建了一个子窗口,如图9-2所示。为什么?
执行【Project】→【ViewSource】菜单命令,打开项目文件Project1,如下所示:
可以看出,程序开始运行就执行了语句Application.CreateForm(TChildForm,ChildForm),创建了一个子窗口。要解决这个问题,执行【Project】→【Options】菜单命令,打开【ProjectOptions】对话框,如图9-4所示。
由图9-4可见,【Auto-createforms】列表框中列出MainForm和ChildForm两个窗口,应把ChildForm去掉。方法是:选择它,单击【>】按钮,将它移到【Availableforms】列表框中,然后单击【OK】按钮,关闭对话框。这时再看项目文件,发现Application.CreateForm(TChildForm,ChildForm)语句不见了。保存文件,运行程序,结果如图9-5所示,符合要求。
9.2.2多文档界面应用程序子窗口的控制
为使多文档界面应用程序更加完善,还要增加一些对子窗口进行控制的功能。
1.窗口菜单
大多数MDI程序主窗口某一主菜单项下都有一个下拉菜单,显示当前打开的所有子窗口的列表,并且标记出当前激活的子窗口,如图9-6所示即为MicrosoftWord中【窗口】主菜单项的下拉菜单,其中列出当前打开的子窗口有3个:10调试、11多媒体和9多文档,9多文档为当前激活子窗口,这个子窗口列表也称“窗口菜单”。使用窗口菜单,用户可以在各个子窗口之间快速切换。
建立窗口菜单,只要将主窗体的WindowsMenu属性设置为带有窗口菜单的主菜单项的Name属性值,那么程序运行时,该主菜单项的下拉菜单中就会显示窗口菜单。
如在上面的例题中,若要求在【窗口】主菜单项中显示窗口菜单,则将主窗体的WindowsMenu属性设置为【窗口】主菜单项的Name属性值,如“NWindows”。这时再运行程序,创建了子窗口后,【窗口】主菜单项下就会显示窗口菜单,如图9-7所示。
每个菜单栏中,只能创建一个窗口菜单。
2.MDI菜单
在多文档界面应用程序中,通常还应有控制子窗口显示方式的菜单命令,称为“MDI菜单”。这些菜单命令一般有【层叠】、【平铺】、【上一个子窗口】、【下一个子窗口】等。增加了MDI菜单的主窗口如图9-8所示。
1)【层叠】菜单命令
执行【层叠】菜单命令,各子窗口从主窗口左上角开始层叠式斜向排列,如图9-5所示。
【层叠】菜单命令,是调用Cascade方法实现的,菜单命令的代码段为:
2)【平铺】菜单命令
执行【平铺】菜单命令,各子窗口水平或者垂直并列放置。因此,【平铺】菜单命令,又可有两个子菜单命令:【水平】和【垂直】。
【平铺】菜单命令,是调用Tile方法实现的。为区分水平和垂直,先用TileMode设置平铺模式。
假设【水平】菜单命令的Name属性值为NwinTileHori,则该菜单命令的处理代码段为:
执行【平铺】→【水平】菜单命令后,各子窗口显示方式如图9-9所示。
假设【垂直】菜单命令的Name属性值为NwinTileVert,则该菜单命令的处理代码段为:
procedureTMainForm.NwinTileVertClick(Sender:Tobject);
执行【平铺】→【垂直】菜单命令后,各子窗口显示方式如图9-10所示。
3)【下一个子窗口】菜单命令
执行【下一个子窗口】菜单命令,可将激活子窗口改为当前子窗口的下一个子窗口。
【下一个子窗口】菜单命令,是调用Next方法实现的,假设【下一个子窗口】菜单命令的Name属性值为NwindowsNext,则该菜单命令的处理代码段为:
4)【上一个子窗口】菜单命令
执行【上一个子窗口】菜单命令,可将激活子窗口改为当前子窗口的上一个子窗口。
【上一个子窗口】菜单命令,是调用Previous方法实现的,假设【上一个子窗口】菜单命令的Name属性值为NwindowsPrevious,则该菜单命令的处理代码段为:
当然,切换当前激活子窗口也可以通过窗口菜单,或者在窗口中直接用鼠标单击要激活的子窗口来实现。
3.关闭子窗口
多文档界面应用程序运行后,单击子窗口右上角的关闭窗口按钮,并不能将子窗口关闭,而只能将子窗口最小化,并放置在主窗口的左下角。若想真正实现子窗口的关闭,还必须为子窗体添加OnClose事件,编写相应的处理代码,其代码段为:
程序运行创建子窗口,单击子窗口关闭按钮,弹出消息框,询问是否关闭子窗口,单击【Yes】按钮,子窗口关闭。
9.3多文档界面中子窗口的菜单设计
在多文档界面应用程序中,只有主窗口有菜单栏,子窗口不显示自己的菜单栏,子窗口使用的菜单项放在主窗口菜单栏中。就是说,主窗口中有的菜单项是对子窗口进行操作的,而对主窗口不起作用。因此,这些菜单项只能用子窗口的菜单设计器进行设计,然后通过一定的手段加入到主窗口的菜单栏中。
9.3.1菜单合并
菜单合并是指将子窗口的主菜单项插入到主窗口的菜单栏中。子窗口创建前,显示的只是主窗口的主菜单项;而子窗口创建后,显示的是主窗口和子窗口所有的主菜单项。如图9-2所示的MDI程序中,假设【编辑】菜单项是子窗口的主菜单项,这就是菜单的合并。菜单的合并是通过菜单项的GroupIndex属性实现的。
为实现这一目的,上面程序的设计要做如下改动:
(1)在主窗体的菜单设计中,将菜单项【编辑】删除,并将【文件】菜单项的GroupIndex属性值设置为1,将【工具】菜单项的GroupIndex属性值设置为3;(2)在子窗体中加入MainMenu组件,打开主菜单设计器,设置【编辑】菜单项,并将该菜单项的GroupIndex属性值设置为2;(3)保存文件,运行程序,显示主窗口如图9-11所示,可见菜单栏中没有了【编辑】
主菜单项,因为该主菜单项是对子窗口的,现没有子窗口,所以不显示【编辑】主菜单项是符合要求的。
执行【窗口】→【新建】菜单命令,创建第一个子窗口,这时程序界面如图9-12所示,显然针对子窗口的【编辑】主菜单项显示出来了。
9.3.2菜单覆盖
菜单覆盖是指用子窗口的主菜单项去覆盖主窗口的主菜单项。如图9-2所示的MDI程序中,假设【编辑】菜单项是主窗口和子窗口都有的主菜单项,子窗口创建前,【编辑】主菜单项是主窗口的;子窗口创建后,【编辑】主菜单项是子窗口的,这就是菜单的覆盖。菜单的覆盖也是通过菜单的GroupIndex属性实现的。
为实现这一目的,上面程序的设计要做如下改动。
(1)在主窗体的菜单设计中,主菜单项保持不变,将【文件】菜单项的GroupIndex属性值设置为1,将【编辑】菜单项的GroupIndex属性值设置为2,将【工具】菜单项的GroupIndex属性值设置为3等。
(2)在子窗体中加入MainMenu组件,打开主菜单设计器,设置【编辑】主菜单项,并将该主菜单项的GroupIndex属性值也设置为2。若要覆盖其他主窗体的主菜单项,则这里的GroupIndex属性值设置为被覆盖的主窗口的主菜单项的GroupIndex属性值。
(3)保存文件,运行程序,显示主窗口如图9-13所示,这时的【编辑】主菜单项是主窗口的。
执行【窗口】→【新建】菜单命令,创建第一个子窗口,程序窗口显示如图9-14所示,表面看起来菜单栏没有什么变化,但这时的【编辑】主菜单项已是子窗口的了。当然菜单项覆盖并不要求同名。
9.4使用MDI模板
从前面的介绍中可以看到,MDI应用程序的设计并不困难,但是却比较烦琐。为方便用户进行MDI应用程序设计,Delphi提供了预先设计好的MDI模板。
9.4.1打开MDI模板
打开MDI模板,要执行如下操作:
(1)执行【File】→【New】→【Other】菜单命令,打开【NewItems】对话框,选择【Projects】
选项卡,如图9-15所示。
(2)选择【MDIApplication】图标,然后单击【OK】按钮,弹出【SelectDirectory】对话框,如图9-16所示。
(3)在对话框的【Directories】列表框中选择Delphi安装目录下的Bin子目录,然后单击【OK】按钮,打开MDI模板,如图9-17所示。
由图9-17可见,该模板的主窗口中有6个组件,一个MainMenu组件并利用这个组件设计好了主窗口的菜单栏,一个OpenDialog组件,一个ActionList组件,一个ImageList组件,一个ToolBar组件,一个StatusBar组件。用户还可以根据需要,向窗体添加其他的组件。
ActionList组件:动作列表组件,位于组件模板的【Standard】选项卡中,用于集中管理程序中各种动作的,通过它可以简化代码编写,提高编程效率。
ImageList组件:图像列表组件,位于组件模板的【Win32】选项卡中,用来设置菜单项前面的位图。
ToolBar组件:工具栏组件,位于组件模板的【Win32】选项卡中,用来设计窗口工具栏。
StatusBar组件:状态栏组件,位于组件模板的【Win32】选项卡中,用来设计窗口中显示程序运行状态的状态栏。
执行【View】→【Forms】菜单命令,打开【ViewForms】对话框,利用对话框打开模板的子窗体,如图9-18所示,用户可根据自己的需要设计子窗体。
9.4.2MDI模板程序代码
在MDI模板中,已经为部分菜单命令编写了程序代码。激活代码编辑器窗口,可以看到主窗体单元文件中几个事件的处理代码如下:
用户可以根据需要,设计自己的程序代码。
习题9
1.什么是多文档界面程序?它与单文档界面程序有什么区别?在多文档界面程序中,主窗口和子窗口是什么关系?
2.设计多文档界面程序的要点是什么?这和多窗体程序的设计有什么异同?
3.如何建立窗口菜单、MDI菜单?
4.如何实现子窗口菜单的合并和覆盖?