http://www.cnblogs.com/pchmonster/archive/2012/01/07/2316012.html

最为一个巩固之前有关窗体和对象的有关知识,下面就建立一个简单的MDI示范程序,这个程序的功能是打开和保存图形文件(包括位图、图标等),为了完成这个任务,我们有一个大概的计划,计划内容如下:

(1)建立主窗体(一个MDI父窗体),包括菜单。

(2)为【File | Open…】 和【File | Save…】菜单选项编写代码。

(3)为Windows菜单上的Cascade、Tile和Arrange All选项编写代码。

(4)建立MDI子窗体。

(5)建立一个About对话框。

(6)然后再回忆和欣赏一下这段工作。

时间就是金钱,即刻就做吧 。

一、创建主窗口窗体

首先创建一个主窗口窗体,一个MDI应用程序的主窗口的FormStyle属性必须设置为fsMDIForm。不但要为应用程序增加File Open和 File Save 对话框,还要增加一个菜单。

1、启动Delphi,并从主菜单选择【File | New | Application】;

2、把主窗体的Name属性设置为MainForm

3、把Caption属性设置为Picture Viewer

4、把FormStyle属性设置为fsMDIForm

好了,下面为此窗体增加一个菜单,利用Delphi特性,引进一个预定义菜单,具体如下:

1、点击组件选项板的Standard标签,并点击MainMenu按钮;

2、把MainMenu组件点击放置到窗体上,具体放到哪个地方无所谓了,因为在运行阶段,代表菜单的图标只是占地方而不显示,这是非可视化组件。

3、把MainMenu组件Name属性改为MainMenu

4、双击MainMenu组件,就会出现Menu Designer对话框;

5、在MainMenu上点击鼠标右键,选择“Insert From Template…”,将出现Insert Template对话框;

6、选择“MDI Frame Menu”并点击OK,此菜单将显示在Menu Designer上,关闭Menu Designer窗口。

现在又回到了主窗体,注意现在窗体上多了一条菜单,此时先不要点击任何子菜单项,我们先准备File Open对话框和File Save对话框:

1、点击组件选项板的Dialogs标签,选择Open Picture Dialog组件,并把它放到窗体上,这也是一个非可视组件。

2、把Open对话框的Name属性改为OpenPictureDialog

3、把Open对话框的Title属性改为“Open a Picture for Viewing”;

4、在窗体再增加一个Save Picture Dialog组件;

5、把此组件的Name属性改为“SavePictureDialog”,把Title属性改为“Save a Picture”;

此时窗体看起来应该像下图:

二、编写【File | Open…】和【File | Save As…】菜单选项代码

下面就准备开始编写代码,Delphi提供了一种很好地编写菜单处理程序的方法,从而使遇到的麻烦最小。还不要建立MDI子窗体,但要充分了解它,并用它来为菜单处理程序编写代码,记住在建立MDI子窗体之前一直不要编译应用程序(因为还没有建立MDI子窗体,编译会出现错误的)

1、在主窗体上选择【File | Open…】菜单项,这样就会在Code Editor中为此菜单项建立一个事件处理程序。

2、为此事件处理程序键入下列代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
procedure TMainForm.Open1Click(Sender: TObject);
var
  Child: TChild;
begin
  if OpenPictureDialog.Execute then
  begin
    Child := TChild.Create(Self);
    with Child.Image.Picture do
    begin
      LoadFromFile(OpenPictureDialog.FileName);
      Child.ClientWidth := Width;
      Child.ClientHeight := Height;
    end;
    Child.Caption := ExtractFileName(OpenPictureDialog.FileName);
    Child.Show;
  end;
end;

这段代码首先打开一个“Open a Picture for Viewing”对话框,并得到一个文件名,如果点击这个对话框的OK按钮,就会产生一个TChild对象(TChild是MDI子类的名字,后面将要建立它。)图像文件被显示到窗体上的Image组件,并且MDI子窗口将会与图像大小相匹配,最后子窗体的标题会显示被选中的图像文件名。

Note

在上面的方法中,ExtractFileName函数是用来从路径中提取文件名的函数,文件名包含在OpenPictureDialog的FileName属性中,相关的函数包括ExtractFilePath、ExtractFileDir、ExtractFileDrive和ExtractFileExt。

Note

前面我们说过所有动态创建的对象到最后都要用Free删除掉,但是上面的代码中好像违反了这个规律,实际上并没有,因为VCL将负责释放分配给MDI子窗口的内存。注意TChild构造程序中的单个参数是Self;这是通知VCL,MDI子窗体的拥有者就是此MDI窗体窗口。当MDI窗体消失时,它将删除所有MDI子对象。

3、按下F12键,切换到主窗体MainForm,现在从菜单中选择【File | Save As…】,将会显示该菜单项处理事件。

4、键入以下代码:

1
2
3
4
5
6
7
8
9
procedure TMainForm.SaveAs1Click(Sender: TObject);
begin
  if SavePictureDialog.Execute then
  begin
    with ActiveMDIChild as TChild do
    { 检查MDI子窗体是否被激活,只保存激活窗体的图像文件}
      Image.Picture.SaveToFile(SavePictureDialog.FileName);
  end;
end;

这段代码比较简洁,头两行是用来检查MDI子窗口是否被激活,如果是激活的窗体,就会显示“Save a Picture”对话框,若用户点击OK,那就将用TPicture类的SaveToFile方法把图像存到盘上去。

Note

前面的这段代码中用到了as操作符,ActiveMDIChild属性返回一个指向TForm对象的指针,在这种情况下,实际上只需要一个指向TChild对象的指针(MDI子类是从TForm类派生来的),as操作符把ActiveMDIChild变量强制转化为一个TChild指针,如果as不能完成这种强制转化,as后面的语句将被忽略。

在继续讲解前,我们先把这个工程保存起来,将Unit1保存为PctViewU.pas,将工程文件dpr保存为PictView。

三、为【Windows】菜单编写代码

1、F12切换到MainForm窗体上,从窗体上MainMenu菜单上选择【Windows | Tile】;

2、只需要为此事件处理程序中输入一行代码即可,最终的事件处理代码如下:

1
2
3
4
procedure TMainForm.ile1Click(Sender: TObject);
begin
  Tile;
end;

3、切换到MainForm窗体,并为菜单【Windows | Cascade】创建代码,如下:

1
2
3
4
procedure TMainForm.Cascade1Click(Sender: TObject);
begin
  Cascade;
end;

4、切换到MainForm窗体,再次为菜单【Windows | Arrange All】创建代码如下:

1
2
3
4
procedure TMainForm.ArrangeAll1Click(Sender: TObject);
begin
  ArrangeIcons;
end;

好,主窗体工作完成了,下面将进行创建MDI子窗体。

四、创建MDI子窗体

MDI子窗体非常简单,实际上不必写任何代码,只要操作下列各步即可:

1、用工具栏上的New Form按钮或者通过主菜单上的【File | New Form】来创建一个新窗体;

2、把它的Name属性设置为Child,Caption属性将被忽略,因为在运行阶段将要动态设置此属性;

3、把FormStyle属性设置为fsMDIChild,为了把这个窗体当做MDI子窗体来处理,这是必须的。

为窗体本身要做的就这些,下面就在此窗体上放置一个Image组件,Image组件将显示用户选择的图形文件。

1、点击组件选项板上的Additional标签,点击Image按钮,并把它放置到Child窗体上;

2、把它的Name属性设置为Image

3、把它的Stretch属性设置为True

4、把它的Align属性设置为alClient,Image组件将缩放到窗体的客户区大小;

5、选择Delphi主菜单的【File | Save】,以MDIChild保存此窗体单元。

6、切换到Code Editor,点击PctViewU标签,然后从Delphi主菜单选择【File | Use Unit】,选择MDIChild单元,点击OK,这样该工程就可以编译了。

此时,整个MDI子窗体看上去如下:

我们的程序还没有完成,因为还差一个About框,此时我们更渴望看到程序的运行,先点击Run按钮,就可以运行程序了,选择【File | Open…】就可以打开任何图形文件了。

注意MDI子窗口会自动缩放它所包含的图形,打开几个文件,然后试一试Window菜单的Cascade和Tile选项。

五、建立About对话框

到目前为止,我们自己随意建立一个属于自己的About框,我的About对话框效果如下:

1、将建立好的About窗体的Name属性设置为AboutBox,BorderStyle属性设置为bsDialog

2、以PVAboutU保存此About对话框窗体单元;

3、切换到Code Editor中的PctViewU标签,从Delphi主菜单选择【File | Use Unit】将PVAboutU单元包含近来;

4、按F12切换到MainForm主窗体,从菜单上选择【Help | About】,这样就产生一个OnClick处理事件;

5、为此事件添加代码如下:

1
2
3
4
procedure TMainForm.About1Click(Sender: TObject);
begin
  AboutBox.ShowModal;
end;

现在运行它,点击Run按钮,试一试Help菜单的About选项,运行效果如下:

六、进一步完善程序

此时这个程序已经可以运行了,但它不等于就没有值得完善的地方。

对于这个程序还有两个问题需要值得注意,它们容易混淆,首先,当启动该程序时,会显示一个空白MDI子窗口,这是因为Delphi应用程序会自动建立所有窗体。我们可以从自动产生的清单中删除MDI子窗体。

1、从Delphi主菜单中选择【Project | Options…】,将显示Project Option对话框;

2、点击Forms标签,其中“Auto-create forms”中显示的就是所有会自动创建产生的窗体清单;

3、点击其中不想要自动创建的窗体Child,选择 >按钮,就会从自动创建列表中删除该子窗口,并把它放置到“Available forms”列表中。

再次运行此程序,这一次将不显示空白MDI子窗体。

Caution

如果要从自动产生清单中删除一个窗体,就必须保证在用它之前要建立一个专门的窗体,如果不建立一个窗体,指向窗体的指针就不能初始化,这就意味着还没有为此指针赋一个有意义的值(记住指针是由Delphi自动产生)。试图用这个指针,其结果将会产生一个非法错误,当从自动产生清单中删除一个窗体后,就必须负责在用它之前建立它。

还有一个问题,就是在MDI窗体上点击关闭按钮时,发现子窗口并没有关闭,而是最小化,因此我们要修改它,使得点击关闭后真正被关闭。

1、在Form Designer中选择Child子窗体,选中窗体本身,确认在Object Inspector的Component Selector中选择的是Child。

2、双击Events页的OnClose事件,添加代码如下:

1
2
3
4
procedure TChild.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

把关闭动作设置为caFree,指示VCL关闭子窗体,并释放与窗体有关的内存,这时点击MDI子窗体关闭按钮就可以正常关闭了。

4、再次运行此程序,证明此程序的表现与前面所述的一样。

<p><strong><font color="#008000">以上代码均在Delphi7中测试通过,示例代码下载:</font><a href="http://files.cnblogs.com/pchmonster/%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95MDI%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F.rar" target="_blank">一个简单MDI应用程序.rar</a></strong></p><

以上代码均在Delphi7中测试通过,示例代码下载:一个简单MDI应用程序.rar

一个简单的MDI示范程序(Delphi)的更多相关文章

  1. 一个简单的P2P传输程序

    写了一个简单的P2P传输程序,在P2P的圈子中传输文件,不过为了简便,这个程序没有真正的传输文件,只是简单的判断一下文件的位置在哪里.这个程序可以处理当有一个peer闪退的情况,在这种情况下,剩下的p ...

  2. IOS开发之小实例--使用UIImagePickerController创建一个简单的相机应用程序

    前言:本篇博文是本人阅读国外的IOS Programming Tutorial的一篇入门文章的学习过程总结,难度不大,因为是入门.主要是入门UIImagePickerController这个控制器,那 ...

  3. iOS开发UI篇—使用嵌套模型完成的一个简单汽车图标展示程序

    iOS开发UI篇—使用嵌套模型完成的一个简单汽车图标展示程序 一.plist文件和项目结构图 说明:这是一个嵌套模型的示例 二.代码示例: YYcarsgroup.h文件代码: // // YYcar ...

  4. 一个简单的DDraw应用程序2

    //------------------------------------------------------------------------- // 文件名 : 6_1.cpp// 创建者 : ...

  5. 一个简单的DDraw应用程序

        阅读排行榜 1. C/C++ 笔试.面试题目大汇总(72915) 2. [STL]list基础(21718) 3. COM笔记-CoCreateInstance(14842) 4. C/C++ ...

  6. Linux内核监控模块-1-驱动模块(LKM)开发(以一个简单的hello world程序为例)

    在上面一篇中介绍到,监控模块要做成一个驱动模块(或者说是可加载模块,LKM),动态的加载到Linux内核中.那么这篇就简单的介绍一下怎样做一个这样的驱动模块.   以简单的hello world程序为 ...

  7. C++ 容器的综合应用的一个简单实例——文本查询程序

    C++ 容器的综合应用的一个简单实例——文本查询程序 [0. 需求] 最近在粗略学习<C++ Primer 4th>的容器内容,关联容器的章节末尾有个很不错的实例.通过实现一个简单的文本查 ...

  8. Cocoa练习01:一个简单的Todo list程序

    写一个简单的todo list程序,界面如下图: 在TextField区域输入文字,点击Add按钮会将文字显示在下面的TableView列表中.TableView列表有2列,第一列是文字的输入时间:第 ...

  9. 一个简单的python爬虫程序

    python|网络爬虫 概述 这是一个简单的python爬虫程序,仅用作技术学习与交流,主要是通过一个简单的实际案例来对网络爬虫有个基础的认识. 什么是网络爬虫 简单的讲,网络爬虫就是模拟人访问web ...

随机推荐

  1. 使用tolua++编译pkg,从而创建自定义类让Lua脚本使用

    步骤一:首先自定义类(这里Himi自定义类名 “MySprite”) MySprite.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 // //  ...

  2. C# json to dynamic object

    dynamic obj = Newtonsoft.Json.JsonConvert.DeserializeObject(json); string greeting = obj.greeting; R ...

  3. Sublime Text 3 安装及简单配置

    Sublime Text 3, 一款不错的文本编辑器, 加上各种插件和IDE就能化身各种语言的编译器, 界面以及多种插件的灵活组合搭配更是让程序员们在码代码这种枯燥的生活中增加一点调剂. 下载地址 点 ...

  4. good mind

    1.如果你能做的事,员工也能做,就让员工做好了. 2.代码是一行一行执行的. 3.如果你找不到NB的人,那就找勤奋点的人.

  5. SpringJUnit4加载类目录下(src)和WEF-INF目录下的配置文件

    路径说明: 一.加载类目录下的配置文件 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:ap ...

  6. rsync介绍

    老套的搬用一下rsync的介绍,rsync是Linux系统下的数据镜像备份工具,从软件的命名上就可以看出来了——remote sync.rsync支持大多数的类Unix系统,无论是Linux.Sola ...

  7. Python利用ConfigParser读取配置文件

    http://www.2cto.com/kf/201108/100384.html #!/usr/bin/python # -*- coding:utf-8 -*- import ConfigPars ...

  8. Connect to the mysql dataase from remote server

    Make sure that the firewall is closed!!!!!!!!! shell command should be like is: mysql -u username -p ...

  9. Repeater, DataList, 和GridView控件的区别

    http://blog.sina.com.cn/s/blog_646dc75c0100h5p6.html http://www.cnblogs.com/phone/archive/2010/09/15 ...

  10. thinkphp多表关联并且分页

    $db_prefix = C('DB_PREFIX'); $Model = new Model(); $data = $Model->table("{$db_prefix}ordern ...