DELPHI程序设计讲座(五)
多文档界面(MDI)应用程序的创建
董占山
(中国农科院棉花所,河南安阳,455112)
本讲重点介绍多文档界面应用程序的开发方法,并选择性地介绍了Dialogs和Win95组件页上的组件以及右键弹出菜单的设计方法。
1.相关组件页概述
本讲提供的样例程序主要用到了Windows的标准对话框、富格式文本编辑组件,分别在Dialogs和Win95组件页上。
1.1 Dialogs组件页
Dialogs组件页上的组件是一类很常用的组件,它们封装了Windows
系统的标准对话框,使在DELPHI中使用这些Windows
标准对话框变得简单易行。该组件页包括了8个对话组件,见
表1所示。本讲将使用并讲解OpenDialog和SaveDialog
两个组件。
表1. Dialogs组件页上的组件
| 图标
|
名称
|
功能
|
|
OpenDialog
|
打开文件对话窗口
|
 |
SaveDialog
|
保存文件对话窗口
|
|
FontDialog
|
设定字体对话窗口
|
|
ColorDialog
|
设定颜色对话窗口
|
| PrintDialog
|
打印对话窗口
|
|
PrinterSetupDialog
|
设定打印机属性对话窗口
|
|
SearchDialog
|
查找对话窗口
|
|
ReplaceDialog
|
查找并替换对话窗口
|
1.2 Win95组件页
Win95组件页上的组件是针对Windows
95的界面风格设计的,包括几个十分常用的组件,如多页控制、状态栏、进度条、增减按钮等组件,详见
表2所示。本讲将用到富格式文本编辑组件。
>表2 Win95组件页上的组件
|
图标
|
名称
|
功能
|
|
TabControl
|
设计可单击标签控制
|
|
PageControl
|
用来设计多页对话框
|
>
|
TreeView
|
设计树形选项列表
|
|
ListView
|
设计可以用多种方式显示的选项列表
|
|
ImageList
|
创建一个可容纳多个同尺寸的图象列表
|
|
HeaderControl
|
设计标题(头)
|
|
RichEdit
|
富格式文本编辑控制
|
|
StatusBar
|
状态栏
|
|
TrackBar
|
跟踪栏
|
|
ProgressBar
|
处理进度条
|
|
UpDown
|
增减按钮
|
|
HotKey
|
设计快捷键
|
2 创建一个MDI应用程序
Delphi 2.0提供了完善的窗体和程序设计模板,对复杂的窗体和程序,使用模板可以显著地提高应用程序的开发效率。下面以开发一个具有MDI
界面的文本编辑器为例,介绍如何使用程序设计模板。
图1 创建新项目对话窗口
(1) 单击“File/New”,打开“New
Items”对话窗口,切换到“Projects”对话页,如
图1
所示;
(2) 选中“MDI
Application”图标,单击〖OK〗按钮,弹出选择文件夹对话窗口,如
图2
所示;
(3) 在目录名编辑框中直接输入一个目录名,如果目录不存在,Delphi
会按指定的名称创建一个目录;
(4) 单击〖OK〗按钮,系统自动创建主窗体和子窗体及其相关的PASCAL
单元等,新创建的主窗体如
图3所示。
图2 设定新项目所在目录对话窗口
图 新创建的缺省MDI主窗体
如果你打开代码编辑窗口,可以看到DELPHI
已经为多数菜单选项、加速按钮创建了必要的事件处理程序。下面以这个MDI程序的框架为基础,一步一步创建一个简单的富格式文本编辑器。
3 改造主窗体
Delphi创建的MDI程序框架的主窗体已经包括了许多内容,有主菜单、菜单选项及其事件处理程序、工具栏及加速按钮、状态栏、一个打开对话组件,这些内容对我们创建MDI
界面的文本编辑器都是必须的。下面我们分几个部分讲解如何完善主窗体。
3.1
向工具栏添加加速按钮
在工具栏上已有6个加速按钮,自左至右分别是打开、保存、剪切、复制、粘贴、关闭。对一般编辑器的工具栏来讲,还应当有一个创建新文档的加速按钮。下面以向工具栏添加一个创建新文档的新建按钮为例介绍如何创建加速按钮。
加速按钮组件在附加组件页(Additional
)上,在组件板上选取加速按钮后,将鼠标移到主菜单下面的Panel组件上,在打开按钮的左边单击,放置一个空白的加速按钮,调整各个按钮的位置,使Panel
组件上的7个加速按钮合理布置。新创建的SpeedButton
的属性见
表3。
表3 SpeedButton的创建属性
|
属性名
|
取值
|
|
Height
|
31
|
|
Hint
|
New|
|
|
Name
|
NewBtn
|
|
Width
|
31
|
到现在为止,这个加速按钮还是一个白板,需要给它赋予一个图象,方法如下:
(1) 双击“Glyph”属性的右半部,弹出类似
图4
的窗口;
图4 图片编辑窗口
(2) 单击〖Load〗按钮,弹出一个打开对话窗口,将文件目录指向“Delphi
2.0\Images\Buttons”,在这个目录下DELPHI提供了许多Bitmap
图象文件,选中“FileNew.bmp”;
(3) 单击〖确定〗按钮将图片装载到图片编辑窗口;
(4) 单击图片编辑窗口的〖OK〗按钮完成。
现在你可以看到这个加速按钮已经拥有了漂亮的外观。这个按钮的功能和主菜单中的“New
”选项一致,所以,将这个加速按钮的OnClick事件处理程序指向FileNewItemClick
即可。方法很简单,单击Object Inspector窗口的“Events
”标签,切换到设定事件处理程序的对话页,单击OnClick的右编辑框中的下箭头钮,弹出一个下拉列表框,选中“FileNewItemClick
”即可。
3.2 为窗体增加右键弹出菜单
为了在编辑窗口中可以使用右键弹出菜单,在主窗体中增加一个PopupMenu
组件,其属性均使用系统创建时的缺省值,使用菜单设计对话窗口,向其中增添3个菜单选项,其名称和属性和事件处理程序见
表4
。
表4 主窗体PopMenu1菜单选项的创建属性
|
标题(Caption)
|
标识名称(Name)
|
事件处理程序(OnClick)
|
|
Cu&t
|
CutItem1
|
CutItemClick
|
|
&Copy
|
CopyItem1
|
CopyItemClick
|
|
&Paste
|
PasteItem1
|
PasteItemClick
|
3.3 添加保存对话组件
对文档窗口中的文本进行修改之后,为了能够将修改好的文本保存到磁盘文件中,必须给文档命名并指定路径,这些任务可以由保存对话组件完成,为此需向主窗体添加一个保存对话组件SaveDialog
。把它添加到主窗体后,按
表5进行属性设置。
表5 SaveDialog组件设计属性
|
属性名
|
取值
|
|
FileEditStyle
|
fsComboBox
|
|
Filter
|
富格式文本
(*.rtf)|*.rtf|文本文件 (*.txt)|*.txt|所有文件|*.*
|
|
Name
|
SaveDialog
|
|
Title
|
保存
|
4
文本编辑窗体的设计
单击“View/Project Manager
”菜单选项,弹出项目管理窗口,选中ChildWin列表项,单击〖View
Form〗按钮,打开MDI子窗体,这是设计文本编辑窗口的起点。
4.1
向窗体添加编辑组件
为了使子窗体能够完成富格式文本编辑功能,需要向窗体添加一个位于Win95
组件页上的RichEdit编辑组件,其属性设置见
style='mso-field-code:"REF _Ref398903614 \\* MERGEFORMAT"'>表6
。再双击Object Inspector窗口中的Lines
属性的右半部,进入串编辑窗口,将其中的内容清空,单击〖OK〗按钮返回。
表6 RichEdit组件的设计属性
|
属性名
|
取值
|
|
Align
|
alClient
|
|
Name
|
Editor
|
|
PopupMenu
|
MainForm.PopupMenu1
|
|
ScrollBars
|
ssVertical
|
|
Wordwrap
|
TRUE
|
4.2
完善文本编辑窗体
DELPHI已经为MDIChild子窗体设置了FormClose
事件处理程序,但是当子窗口关闭前,需要检查一下其上的文本是否已经改变,如果改变了并且没有保存,弹出提示窗口,让用户确认是否保存文本。通过FormCloseQuery
事件处理程序可以达到这个目的。
在设计FormCloseQuery事件处理程序之前,还需要在TMDIChild
类声明的Public部分添加与此文本编辑窗口相关联的文件名串变量:
PathName: string;
FormCloseQuery事件处理程序如下:
procedure
TMDIChild.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
Const
SWarningText = 'Save changes to %s?';
begin
if Editor.Modified then
begin
case
MessageDlg(Format(SWarningText,[PathName]),mtConfirmation,
[mbYes,mbNo,mbCancel],0) of
idYes
:
MainForm.FileSaveItemClick(Self);
idCancel :
CanClose := False;
end;
end;
end;
在这个事件处理程序中,调用了主窗体中的FileSaveItemClick
事件处理程序,所以在单元中要声明使用主窗体单元Main;另外,Format
是Object Pascal的一个系统函数,在SysUtils
中定义,MessageDlg是在Dialogs
单元中定义的一个窗口函数,所以在这个单元的实现部分,应当添加一条使用单元的声明语句:
uses Main,
SysUtils, Dialogs
5
进一步完善主窗体
文本编辑窗体设计完成后,下一步的工作是进一步完善主窗体的事件处理程序,以实现对文本编辑窗体的操纵,来完成文档的打开、编辑、保存等功能。首先在实现部分的开头加上:
Uses MDIChild;
5.1
编辑功能的实现
要实现文本的编辑功能,主要是设计Edit
菜单中各个功能选项的OnClick事件处理程序。下面是Cut
、Copy和Paste三个菜单选项的OnClick
事件处理程序。这个菜单的所有操作均是对活动文档子窗口而言的。
procedure
TMainForm.CutItemClick(Sender: TObject);
begin
if ActiveMDIChild <> nil then
TMDIChild(ActiveMDIChild).Editor.CutToClipboard;
end;
procedure
TMainForm.CopyItemClick(Sender: TObject);
begin
if ActiveMDIChild <> nil then
TMDIChild(ActiveMDIChild).Editor.CopyToClipboard;
end;
procedure
TMainForm.PasteItemClick(Sender: TObject);
begin
if ActiveMDIChild <> nil then
TMDIChild(ActiveMDIChild).Editor.PasteFromClipboard;
end;
5.2
实现编辑菜单的动态感知功能
如果当前文档中选定了文本,那么可以使用Cut
和Copy选项,否则,应当禁止使用;如果剪贴板上有文本存在,可以使用Paste
选项,否则,应禁止使用。为了在打开编辑窗口时,能够动态地设定菜单选项的可用状态,为Edit
菜单创建一个OnClick事件处理程序,以完成这项功能。同时,也要把PopupMenu1
的OnClick事件处理入口指向它。
procedure
TMainForm.Edit1Click(Sender: TObject);
Var
HasSelection : Boolean;
begin
PasteItem.Enabled :=
Clipboard.HasFormat(CF_TEXT);
PasteItem1.Enabled :=
PasteItem.Enabled;
HasSelection := False;
if ActiveMDIChild <> nil then
HasSelection :=
TMDIChild(ActiveMDIChild).Editor.SelLength > 0;
CutItem.Enabled := HasSelection;
CopyITem.Enabled := HasSelection;
CutItem1.Enabled := HasSelection;
CopyITem1.Enabled := HasSelection;
end;
在这段程序中,为了检查剪贴板上是否有文本存在,使用了Clipboard
函数,这个函数的定义在Clipbrd单元中,所以在本单元的实现部分的uses
语句中加上Clipbrd单元。
5.3
文件的打开和保存功能的实现
为了在创建一个新文档时,给文件起一个默认的名字,用来标记文档子窗口,在单元的实现部分添加一个字符串类型常量:
Const
DefaultFileName : String = 'NONAME';
文件菜单的新建(New)选项的OnClick
事件处理程序如下:
procedure
TMainForm.FileNewItemClick(Sender: TObject);
var
Child: TMDIChild;
Name : string;
begin
Name := DefaultFileName +
IntToStr(MDIChildCount + 1);
Child := TMDIChild.Create(Application);
Child.Caption := Name;
Child.PathName := Name;
end;
对DELPHI自动创建的CreateMDIChid
私有方法进行必要的修改,将它用于创建一个文档子窗口并打开指定的文档填充文本编辑器。
procedure
TMainForm.CreateMDIChild(const Name: string);
var
Child: TMDIChild;
begin
Child := TMDIChild.Create(Application);
Child.Caption := ExtractFileName(Name);
Child.PathName := Name;
with Child.Editor do begin
Lines.LoadFromFile(Child.PathName);
SelStart := 0;
Modified := False;
end;
end;
DELPHI自动创建的“Save”和“Save
as”菜单项的OnClick事件处理程序为空,需要设计者完成具体功能。本例中二者的OnClick
事件处理程序如下:
procedure
TMainForm.FileSaveItemClick(Sender: TObject);
begin
if ActiveMDIChild <> nil then
with
TMDIChild(ActiveMDIChild) do begin
if
pos(DefaultFileName,PathName) <> 0 then
FileSaveAsItemClick(Sender)
else begin
Editor.Lines.SaveToFile(PathName);
Editor.Modified := False;
end;
style="mso-spacerun:
yes"> end;
end;
procedure
TMainForm.FileSaveAsItemClick(Sender: TObject);
begin
if ActiveMDIChild <> nil then
with
TMDIChild(ActiveMDIChild) do begin
SaveDialog.FileName := PathName;
if
SaveDialog.Execute then begin
PathName := SaveDialog.FileName;
Caption := ExtractFileName(PathName);
FileSaveItemClick(Sender);
end;
end;
end;
至此,一个初级多文档界面的文本编辑器已经设计好了,如果打入程序时没有键入错误,单击[F9]
键就可以编译并运行它。这个文本编辑器比Windows提供的Notepad
还要高级一些。由此可知:对DELPHI来讲,设计一个实用的MDI
程序是相当简单的。
©董占山Zhanshan Dong
|