1、第 6 章 创建和使用对话框1第 6 章 创建和使用对话框精讲对话框是一种用户界面,几乎每一个 Windows 程序都使用对话框与用户进行交互。对话框可能是一个简单的只含有 OK 按钮的消息框,也可以是一个复杂的数据输入表单。对话框上有一些方便用户输入的控件,对话框依靠这些控件与用户进行交互,其实质是一个接收消息的窗口。在本章节我们主要讲述模式对话框和无模式对话框的原理和使用方法,下一章将详细介绍各种控件的使用。你将学习创建一个对话框,使用对话框模板编辑一个对话框资源,并在程序中调用对话框的方法。6.1 对话框的基本原理6.1.1 对话框的工作原理在创建一个对话框之前,我们先来了解一下对话框是
2、如何工作的,对话框的数据来自三方面:对话框资源、对话框对象、和一个文档对象:1 对话框资源对话框资源是一个用户输入或取得数据的图形界面。这个图形界面是使用 Develop Studio 的对话框编辑器在对话框模板上创建的,程序员可以在对话框模板上增加并编辑控件,生成对话框资源。当应用程序运行时,就可以得到一个对话框。2 对话框对象MFC 使用 CDialog 类来描述对话框,它是 CWnd 类的派生类。在 CWnd 类的基础上增加了数据交换的功能。当创建一个新的对话框资源后,使用 ClassWizard 可以创建一个对话框类的派生类。对话框对象实现了对话框和应用程序之间的通信。在应用程序中定义
3、一个对话框对象后,在对话框显示前,可以通过访问对话框对象的成员变量为一个对话框的控件初始化,在对话框关闭后,可以通过访问对话框对象的成员变量获得用户的输入数据。3 文档对象MFC 使用文档对象描述应用程序处理的数据,用户输入的数据要进一步的处理,通常要先存贮到文档对象中。例如:一个学生记录处理的应用程序,用户通过一个对话框输入学生记录并贮存到一个文件中。应用程序的处理顺序是:用户在对话框中输入信息,通过对话框对象得到输入信息,将输入信息整理到文档对象中,使用序列化函数将文档对象存贮到一个文件中,所以文档对象扮演了一个很重要的数据交换的角色。MFC 使用以上三者实现用户与应用程序之间数据交换,数
4、据交换流程见图 6-1 所示,遵循四个步骤。VC+6 简明教程2图 6-1 对话框基本原理6.1.2 对话框的类型对话框分为模式对话框和无模式对话框两种。当一个模式对话框打开了,在其关闭之前,用户不能转向其它用户界面对象,只能与该对话框进行交互。我们平时接触到的对话框,大多数都是模式对话框,例如,一个执行菜单命令 File-Save 后,Save 对话框被打开后,用户不能再做其它工作,只能保存完文件或取消保存文件,关闭对话框窗口后,才能做其它工作。无模式对话框恰恰相反,当用户打开一个无模式对话框,对话框停留在屏幕上,仍然允许用户与其它用户界面对象进行交互。无模式对话框最典型的例子是在 Word
5、 中使用的查找与替换对话框,打开该对话框后,可以交替地进行文档编辑,和查找替换操作。从第一节的介绍可以看到对话框的设计任务主要包括对话框资源模板的设计,对话框类的设计和对话框的运行,绝大多数对话框的创建任务,模式对话框和无模式对话框都是相同的,只有在对话框与应用程序代码的交互中,也就是对话框的运行中,两者有明显的区别。6.2 设计对话框资源6.2.1 创建对话框使用 AppWizard 生成的单文档或多文档应用程序,只有一个默认的 About 对话框,用于显示应用程序版本信息。需要使用对话框模板创建自己的对话框资源。Develop Studio 提供的对话框模板创建了一个基本界面,包括一个 O
6、K(确定)按钮和一个Cancel(取消)按钮等。你可以移动、修改、删除这些控件,或者是增加新的控件到对话框模板,构成应用程序所需的对话框资源。创建一个对话框资源到工程的步骤:(1) 使用 AppWizard 生成一个单文档的 MFC 应用程序 Exam6_1。(2) 选择 Insert-Resource 菜单命令。(3) 在弹出的 Insert Resource 对话框左边的列表中选择 Dialog,单击 New 按钮。Public:data memberdocumentxxxxxxxxxxxxxxxxxxxxxxxxxxxx创建对话框模板 1数据交换和验证 2定义对话框类和 3公有成员变量
7、运行对话框,修改 4 文档对象第 6 章 创建和使用对话框3(4) 在项目工作区中选择 ResourceView 面板,展开 Dialog 文件夹,可以看到增加了一个对话框资源 IDD_DIALOG1,如图 6-2 所示,双击 IDD_DIALOG1,在编辑区出现一个对话框模板。图 6-2 Exam6_1 对话框设计新建对话框资源6.2.2 增加控件一个控件是能够放置在一个对话框中,提供应用程序与用户交互的某种功能。例如,Edit Box 提供用户文本输入的场所,一组 Radio Button 提供用户对某一主题的单项选择。 MFC 将控件设计为对话框窗口的子窗口,控件通过事件通知消息与父窗口
8、联系。在一个对话框资源中增加控件的操作十分方便,只需从图 6-2 所示的控件工具栏中选中要增加的控件,再将此控件拖拉至对话框模板中的确定位置上,松开鼠标按键即生成一个控件。调整控件的位置和大小的操作与 Word 中对文本框的操作完全一样。在默认情况下,控件工具栏总是打开的,如果没有打开,可以在 Develop Studio 工具栏后的空白处,单击鼠标右键,在弹出的快捷菜单中选择 Controls,便可打开控件工具栏。图 6-3 中列出了 VC 6.0 中支持的标准控件名称,我们可以很方便地从控件工具栏中生成新的控件,但每一种控件都具有不同的特性,需要学习和掌握。对话框模板对话框资源 ID 控件
9、工具栏Check BoxGroup BoxPicture Edit ControlVertical Scroll BarProgressHot KeyTree ControlAnimateDate Time PickerCustom ControlIP AddressExtended Combo BoxCombo BoxTab ControlMonth CalenderRadio ButtonButtonList BoxRich EditList ControlSliderSelection ToolStatic TextHorizontal Scroll BarSpinVC+6 简明教程4图
10、 6-3 标准控件 下面我们试着设计一个可以输入 5 门功课成绩的输入窗口,在上一节生成的对话框资源IDD_DIALOG1 中做以下操作,得到如图 6-4 所示的对话框:(1) 调整对话框模板窗口大小,将 OK 和 Cancel 按钮移到窗口的底部。(2) 控件工具栏中选中 Static Text(静态文本)控件,拖到对话框模板中。(3) 通过复制和粘贴操作,生成其它四个 Static Text 控件。(4) 控件工具栏中选中 Edit Box 控件(编辑框) ,拖到对话框模板中。(5) 通过复制和粘贴操作,生成其它四个 Edit Box 控件图 6-4 EX6 对话框设计增加控件6.2.3
11、设置控件属性一个控件相关的属性设置决定了一个控件可操作行为和显示。例如,控件的 ID 是控件的一个重要属性,MFC 内部是以控件 ID 来标识一个控件,当消息产生后,是哪一个控件需要进行处理,MFC内部使用的是控件 ID。属性的设置是在与每个控件相对应的属性对话框中进行的,单击鼠标右键,在弹出的快捷菜单中选择 Properties,打开属性对话框。每一种控件的属性对话框都有所不同,与其特性相关,在下一章我们将详细介绍一些常用控件的属性含义。对上一节的对话框 IDDDIALOG1 中的控件作属性设置:(1) 鼠标选中第一个 Static Text 对象,单击鼠标右键,在弹出的快捷菜单中选择 Pr
12、operties,弹出属性对话框,如图 6-5 所示。图 6-5 属性对话框设置(2) 修改 Caption 右边的文本框,输入“高等数学” ,单击关闭按钮,关闭属性对话框。(3) 重复步骤(1)(2),将其它四个 Static 控件的 Caption 改为“大学物理” , “大学英语” , “哲学”和第 6 章 创建和使用对话框5“计算机基础” 。(4) 同样的操作打开 5 个 Edit Box 控件的属性对话框,修改 ID 为IDC_SCORE1、IDC_SCORE2 、IDC_SCORE3、IDC_SCORE4、IDC_SCORE5。(5) 打开按钮 OK 的属性对话框,修改 Capti
13、on 为“确定” 。(6) 打开按钮 Cancel 的属性对话框,修改 Caption 为“取消” 。操作完毕,对话框如图 6-6 所示。图 6-6 EX6 对话框设计设置属性同样,对话框的属性设计也是在对话框的属性对话框中设置,在对话框任意空白处单击鼠标右键,在弹出的快捷菜单中选择 Properties,如图 6-7 所示。在 Caption 中填写“成绩录入” ,将成为对话框的标题,单击 Font 会弹出字体对话框,能设置对话框中显示的字体格式。其它的几个标签页还提供了选项,可以修改对话框窗口的显示样式,可以自己试一试。图 6-7 对话框属性设置 6.2.4 组织和安排控件当选择了一个对话
14、框资源进入对话框编辑器时,Develop Studio 的菜单栏上会增加一个菜单Layout,如图 6-8 所示。Layout 菜单提供了在对话框模板中合理布置控件的功能菜单项。 Align 提供了控件的六种对齐方式:左对齐、右对齐、上对齐、下对齐、水平居中、垂直居中。Space Evenly 提供了两种等间距方式:垂直方向等间距、水平方向等间距。VC+6 简明教程6Make Same Size 提供了三种等尺寸方式:宽相等、高相等、两者都相等。Arrange Button 提供了两种组织按键的方式:底部排列、右边排列。Center in Dialog 提供了两种居中方式:水平居中、垂直居中。
15、Flip 用于水平反方向显示控件及窗口标题。Size to Content 命令根据内容决定控件的大小,例如,按钮的大小由按钮上的显示文本决定。图 6-8 Layout 下拉菜单 通过上面几个菜单项的操作能够很方便地齐整控件的摆放位置。现在我们可以整理一下IDD_DIALOG1 中 摆放凌乱的控件:(1) 确定第一个和最后一个 Static Text 控件的位置,同时选中 5 个 Static Text 控件,执行菜单命令Layout-Make Same Size-width(2) 执行菜单命令 Layout-Align-Bottom,水平对齐 5 个控件。(3) 执行菜单命令 Layout-
16、Space Evenly-Across,使 5 个控件水平等间距。(4) 选择“哲学” ,执行菜单命令 Layout-Size to Content,微调控件位置(5) 确定第一个和最后一个 Static Text 控件的位置,同时选中 5 个 Static Text 控件,执行菜单命令Layout-Align-Bottom 和 Layout-Space Evenly-Across。操作完毕,可以看到控件整齐地排放在对话框模板上,如图 6-9 所示。图 6-9 EX6 对话框设计整理控件在 Windows 环境中通常提供两种操作方法,鼠标操作方式和键盘操作方式,使用鼠标可以直接点击控件进行访问
17、,使用键盘访问控件需要通过 Tab 键顺次找到某个控件。Tab Order 规定了使用 Tab 键访问控件的顺序,一般 Tab Order 是控件生成的顺序,执行菜单命令 Layout-Tab Order 可以显示并修改 Tab Order,对 IDD_DIALOG1 执行菜单命令 Tab Order 如图 6-10 所示。图 6-10 显示 Tab Order第 6 章 创建和使用对话框7改变 Tab Order 的方法既简单又直观,执行了 Tab Order 命令出现了顺序号之后,按你所想要的访问顺序依次点击每一个控件,完成后,点击空白处就可以了。读者可以试练习将上图的 Tab 顺序变成先
18、访问第一个 Edit Box,访问完所有的 Edit Box 后再访问 Button。6.2.5 测试对话框当构造好一个对话框后,还不能立即在应用程序中运行对话框,MFC 提供了 Test 命令,使程序员在设计阶段就能够测试对话框的运行效果。测试对话框的方法有:(1) 菜单命令 Layout-Test(2) Dialog 工具栏上的 Test 按钮(3) 快捷键 Ctrl+T测试对话框 IDD_DIALOG1,试着使用文本框输入,并使用 Tab 键是否符合要求。如图 6-11 所示。图 6-11 Exam6_1 对话框设计测试对话框6.3 设计对话框类一个对话框资源要加入到一个窗口应用程序中,
19、首先要为它创建一个对话框类,是 CDialog 类的派生类。应用程序运行时,窗口操作系统使用对话框类为对话框在内存开辟空间。在 Win32 API 类型的窗口应用程序中,都是直接通过控件 ID 来访问对话框上的控件的,而 MFC提供了连接变量来标识控件,连接变量是对话框的成员变量,同时对话框类有一套交换和验证数据的方式。6.3.1 创建对话框类创建对话框类的步骤如下:1 保存已创建好的对话框模板。测试对话框窗口VC+6 简明教程82 确保新的对话框资源在对话框编辑器中打开状态下,打开 ClassWizard 窗口。打开 ClassWizard 的方式有 3 种:(1) 窗口菜单命令 View-
20、ClassWizard(2) 快捷菜单命令 ClassWizard(3) 快捷键:Ctrl+w3 在弹出的 Adding a Class 对话框中,如图 6-12 所示,选择 Create a new class 单选钮,单击 OK 按钮。图 6-12 “增加类”对话框 4 在随后弹出的 New Class 对话框中,如图 6-13 所示,只需填写类的名称:CScoreDlg,单击 OK 按钮。关闭 ClassWizard,对话框类的创建就完成了。图 6-13 填写新类名称在 Workspace 窗口的 ClassView 面板中,可以看到增加了一个新的类 CScoreDlg,选择 FileV
21、iew 面板,在 Header Files 和 Source Files 文件夹中,可以看到该类的头文件和实现文件,文件名是类名除去开头的类标志“C” 。填写类名第 6 章 创建和使用对话框9图 6-14 新增对话框类及文件在创建新类的时候,要注意新类的对话框 ID 一定要与对话框资源 ID 一致,这些 ID 告诉对话框类,在对话框窗口创建前,哪一个对话框资源要被检查,初始化控件并显示。尤其在创建好对话框后,不能随意地改动对话框资源 ID 和删除对话框资源。6.3.2 创建对话框成员变量创建好一个对话框类后,可以增加类的成员变量来操作对话框上的控件。出于不同的操作目的,MFC 提供了两种类型的
22、成员变量,如表 6-1 所示。表 6-1 对话框类的成员变量类型类 型 描 述Values 值类型的成员变量。用于控件的值控制,可以有多种数据类型,由所连接的控件类型决定。例如,Edit Box 控件可以有CString 型或 int 型。Radio Button 可以是 int 型。 Controls 控件类型的成员变量,实质是该控件类的一个对象。创建了一个控件对象,就可以通过该对象使用控件类的方法对控件进行操作,例如,在程序运行时为 Combo Box 加入选择项,设置控件是否有效或可见等。例如,创建了 CScoreDlg 类后,需要为对话框中每一个 Edit Box 控件创建一个值类型的
23、成员变量,来取得用户在 EditBox 输入的数据,增加控件成员变量的步骤如下:(1) 打开 ClassWizard 窗口,选择 Member Variables 标签页,Class name 下拉列表中选择CScoreDlg 类。这时,对话框中可以创建成员变量的控件 ID 出现在下方的 Control IDs 列表中,如图 6-15 所示。VC+6 简明教程10图 6-15 增加一个对话框类的成员变量(2) 选择一个 IDC_SCORE1,单击 Add Variable 按钮,弹出 Add Member Variable 对话框,Member variable name 编辑框中填写变量名为
24、:m_score1 ,确认 Category 下拉框中为:Value ,在Variable type 下拉框中选择为: int。(3) 单击 OK 按钮,回到 ClassWizard 窗口,可以看到新增的成员变量出现在列表中。同样的操作增加其它四个成员变量。(4) 如果增加成员变量时操作有误,例如变量名错误,变量类型错误,选择该成员变量,单击Delete Variable 按钮删除该变量,再重新创建。创建好的成员变量如图 6-16 所示。图 6-16 成员变量列表创建好成员变量后,我们来检查一下 ClassWizard 作了哪些工作:变 量 类 型 变 量 名 称第 6 章 创建和使用对话框1
25、1(1) 展开项目工作区的 ClassView 面板中的 CScoreDlg 类,在树目录上出现了刚创建的成员变量。(2) 双击 CScoreDlg 的类名,进入该类的头文件 ScoreDlg.h,可以找到对话框类定义的代码,如程序清单 6-1 中所示。程序清单 6-1:对话框成员变量定义示例class CScoreDlg : public CDialog/ Constructionpublic:CScoreDlg(CWnd* pParent = NULL); / standard constructor/ Dialog Data/AFX_DATA(CScoreDlg)enum IDD = I
26、DD_DIALOG1 ;int m_score1;int m_scroe2;int m_score4;int m_score5;int m_score3;/AFX_DATA. .其中呈灰色显示的,在宏“AFX_DATA(CScoreDlg)AFX_DATA”之间定义的是用ClassWizard 创建的成员变量。需要注意的是,所有 ClassWizard 产生的灰色显示的代码,不要在文件中直接修改,而应在 ClassWizard 工具中进行修改,不然容易引起错误。(3) 打开该类的构造函数,可以看到 ClassWizard 自动加入了成员变量的初始化代码,如程序清单6-2 所示。程序清单 6-2
27、:对话框类的构造函数CScoreDlg:CScoreDlg(CWnd* pParent /*=NULL*/): CDialog(CScoreDlg:IDD, pParent)/AFX_DATA_INIT(CScoreDlg)m_score1 = 0;m_scroe2 = 0;m_score4 = 0;m_score5 = 0;m_score3 = 0;/AFX_DATA_INITVC+6 简明教程126.3.3 对话框数据交换和校验对话框的值类型的成员变量存储了与控件相对应的数据,对框话打开时,用户可以修改控件的数据,有时需要应用程序对用户的输入进行及时反馈,这时数据成员变量需要与控件交换数据
28、,以完成输入输出功能。对于这种功能 MFC 是靠 CDataExchange 类提供的数据交换(DDX:Dialog Data Exchange)机制来完成的,该类提供了数据有效机制(DDV:Dialog Data Validation)当在对话框类中增加一个数据成员变量,有时需要规定数据的有效性校验规则,例如,成绩录入对话框中,应设置各门课的成绩应在 0100 的范围内。在应用程序运行的时候,当用户输入数据拷贝到数据成员变量时,DDV 机制被调用,如果有效性校验失败,即用户输入一个不合理的数据时,将出现一个错误信息对话框,并返回到出现错误输入的控件。有效性校验的设置也是在 ClassWiza
29、rd 中完成的。我们再回到成绩录入的 Member Variables 标签页,选择表示成绩输入框的 m_score1,在标签页的下方会出最大值和最小值的输入框,如图 6-17 所示,填入 0 和 100。如果一个 CString 型的数据成员变量对应的通常是字符串的长度。图 6-17 添加数据成员变量的有效范围对话框类调用 DoDataExchange 函数来实现 DDV 和 DDX,对应图 6-17 的 CScoreDlg 类的DoDataExchange 代码如程序清单 6-3 所示。程序清单 6-3:对话框类的 DoDataExchange 函数void CScoreDlg:DoDat
30、aExchange(CDataExchange* pDX)CDialog:DoDataExchange(pDX);/AFX_DATA_MAP(CScoreDlg)DDX_Control(pDX, IDOK, m_OK); /控件对象数据交换DDX_Control(pDX, IDC_SCORE5, m_Score5Edit); /文本框数据交换DDX_Control(pDX, IDC_SCORE4, m_Score4Edit);DDX_Control(pDX, IDC_SCORE3, m_Score3Edit);第 6 章 创建和使用对话框13DDX_Control(pDX, IDC_SCORE
31、2, m_Score2Edit);DDX_Control(pDX, IDC_SCORE1, m_Score1Edit);DDX_Text(pDX, IDC_SCORE2, m_score2);DDX_Text(pDX, IDC_SCORE3, m_score3);DDX_Text(pDX, IDC_SCORE4, m_score4);DDX_Text(pDX, IDC_SCORE5, m_score5);DDX_Text(pDX, IDC_SCORE1, m_score1);DDV_MinMaxInt(pDX, m_score1, 0, 100); /最大最小值检查/AFX_DATA_MAPp
32、DX 指针指向一个 CDataExchange 对象,DDX 函数来完成控件和数据成员变量之间的数据交换,DDV 完成数据有效性检查。DDX 和 DDV 适用于文本框、复选框、单选按钮、列表框和组合框。当程序需要交换数据时,不需要编写代码调用 DoDataExchange 函数,而应该调用CWnd:UpdateData()函数,UpdateData()函数内部调用了 DoDataExchange 函数。UpdateData()函数只有一个 BOOL 类型的参数,决定数据交换的方向:(1) UpdateData(false)将对话框对象的数据成员变量的值拷贝到对话框中的控件。(2) Update
33、Data(true )将对话框中控件的值拷贝到对话框对象的数据成员变量。你可以随时在需要进行数据交换时调用相应的 UpdateData()函数,例如,在成绩录入的对话框中增加两个控件,一个是 Edit Box 用于显示总分,另一个是 Button 用于计算总分,则在 Button 的 Click 事件处理函数中,就需要先调用 UpdateData(true)获取用户录入的 5 门功课的成绩,在计算总分后,调用UpdateData(false),将总分显示在 Edit Box 中。在默认的 CDialog:OnInitDialog()函数中调用了 UpdateData(false),这样在对话框
34、创建的时候,数据成员的初值就会反映到相应的控件上。若用户单击 OK(确定)按钮关闭对话框, CDialog:OnOK()函数会调用 UpdateData(true),将控件中的数据传给数据成员变量,如图 6-18 所示。图中说明了对话框的控件与对话框对象之间的数据交换是由框架自动完成的,而对话框对象与文档对象之间的数据交换则需要编写代码。图 6-18 数据交换和验证在应用程序中的实现 DDXPublic:data memberdocumentxxxxxxxxxxxxxxxxxxxxxxxxxxxx框架处理对话框和对象之间的数据交换和验证编写代码在文档对象和对话框对象之间交换数据DDX and
35、DDVVC+6 简明教程146.4 运行对话框创建好一个对话框资源和对话框类,要在应用程序中运行对话框,通常要在一个菜单命令下打开一个对话框。所以,首先要定义一个菜单项和相应的菜单命令处理函数,在函数中编写代码运行对话框。运行模式对话框和无模式对话框有所不同,下面结合实例详细介绍两种对话框运行的方法。6.4.1 模式对话框在应用程序中使用得更多的还是模式对话框,模式对话框的运行分两个步骤:(1) 创建一个对话框对象(2) 调用 CDialog:DoModal()函数打开对话框DoModal()函数负责模式对话框的创建和撤消。在创建对话框时,DoModal() 的任务包括:装载对话框资源、调用
36、OnInitDialog()初始化对话框和将对话框显示在屏幕上。完成对话框的创建后,DoModal()启动一个消息循环,以响应用户的输入。这时,用户只能与对话框进行交互,其它用户界面对象收不到输入信息,只有终止模式对话框后才能进行其它工作。若用户在对话框内单击了系统默认的 OK(确定)按钮,则 CDialog:OnOK()函数将被调用,OnOK()首先调用 UpdateData(true)函数,将数据从对话框中的控件拷贝到数据成员变量,再调用CDialog:EndDialog()关闭对话框,并返回值 IDOK。若用户在对话框单击了系统默认的 Cancel(取消)按钮,则 CDialog:OnC
37、ancel()函数将被调用,该函数只调用 CDialog:EndDialog()关闭对话框,并返回值 IDCANCEL。程序可以根据返回值是 IDOK还是 IDCANCEL 来判断用户关闭对话框按的哪一个键。下面我们将运行成绩录入对话框,当按“确定”按钮返回时,将其显示在主窗口视图上。为此,要定义对应的文档对象。步骤如下:1 增加文档类公有变量并设置初值int 型成员变量数组 score5,存放 5 门课程成绩;int 型成员变量 TScore,用来存放总分。在构造函数中设置数组 score 和 TScore 的初值都为 0。2 在视图类 OnDraw 函数中添加代码实现成绩的输出具体代码见程
38、序清单 6-4 所示粗体部分。程序清单 6-4:OnDraw 函数输出 int 型文档类成员变量的值void CExam6_1View:OnDraw(CDC* pDC)CExam6_1Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);/ TODO: add draw code for native data herepDC-TextOut(0,0,“高等数学 大学物理 大学英语 哲学 计算机基础 总分“) ;/输出表头CString str;/将 int 型数据转换为格式字符串str.Format(“%10d%16d%16d%16d%16d%18d“,p
39、Doc-score0,pDoc-score1,pDoc-score2,pDoc-score3,pDoc-score4,pDoc-TScore ); pDC-TextOut(0,20,str); /输出成绩第 6 章 创建和使用对话框153 增加一个菜单项在“编辑”菜单的最下面增加一个菜单项,Caption 为“成绩录入” ,菜单 ID 为ID_SCOREFILLING。4 为新增菜单在文档类定义消息处理函数用 ClassWizard 在文档类生成菜单命令处理函数 OnScorefilling()。5 编辑代码完成下面的功能(1) 创建对话框对象。(2) 运行成绩录入对话框,并把对话框数据成员的
40、值拷贝到文档类成员变量 score 数组中。(3) 计算总分。(4) 更新视图。具体代码见程序清单 6-5 所示粗体部分。程序清单 6-5:调用模式对话框示例void CExam6_1Doc:OnScorefilling() / TODO: Add your command handler code hereCScoreDlg dlg; /创建对话框对象if(dlg.DoModal()=IDOK )/调用对话框并判断返回值为 IDOK /使用对话框对象的成员变量的值修改文档对象的成员变量score0=dlg.m_score1 ; score1=dlg.m_score2 ;score2=dlg.
41、m_score3 ;score3=dlg.m_score4 ;score4=dlg.m_score5 ;for(int i=0;iUpdateAllViews(NULL); /更新视图6 加入头文件在 Exam6_1Doc.cpp 文件的头部的所有的 include 语句之后加入语句:#include “ScoreDlg.h”7 编辑运行程序执行菜单命令“编辑”-“成绩录入” ,弹出“成绩录入”对话框,输入各门课的成绩后,按“确定”退出对话框,应用程序主窗口中显示刚刚输入的各课成绩和总分。6.4.2 对话框初始化对话框的初始化工作包括:为控件赋初始值(如:文本框的显示值,单选按钮,复选框的选中
42、状态等) ,或者设置控件的初始状态(如:控件是否可用、是否显示,下拉框中的选择项等) 。为控件赋初始值也就是为对话框对象的数据成员变量赋初值,可在两个位置进行:VC+6 简明教程161 对话框类的构造函数系统一般在对话框类的构造函数中,为数据成员变量赋初值。2 对话框对象创建后对话框对象一般在一个菜单命令处理函数中创建,创建后在对话框调用之前,也就是在 DoModal ()函数调用之前,可以通过对象调用数据成员变量为其赋初值。修改程序清单 6-5 中的 OnScorefilling()函数,实现每次调用成绩录入对话框时,以文档对象 score 数组中现有的成绩为初始值,作为对当前视图的修改。增
43、加的代码见程序清单 6-6 所示粗体部分。程序清单 6-6:模式对话框数据成员赋初值void CExam6_1Doc:OnScorefilling() / TODO: Add your command handler code hereCScoreDlg dlg; /创建对话框对象dlg.m_score1=score0; /初始化对话框数据成员dlg.m_score2=score1;dlg.m_score3=score2;dlg.m_score4=score3;dlg.m_score5=score4;if(dlg.DoModal()=IDOK )score0=dlg.m_score1 ; sc
44、ore1=dlg.m_score2 ;score2=dlg.m_score3 ;score3=dlg.m_score4 ;score4=dlg.m_score5 ;for(int i=0;iUpdateAllViews(NULL);修改后再次编译运行程序,可以看到每次对话框打开时,控件的初值都能反应当前视图的显示。程序清单 6-6 也给出的调用对话框的一个范例,一般遵循四个基本步骤:(1) 创建对话框对象(2) 初始化对话框(3) 调用对话框(4) 确定返回后的处理图 6-18 中文档对象和对话框对象之间交换数据通常是在第(2) 、(4)步编写代码完成的。设置控件的初始状态,可以直接在对话框资
45、源中各控件的属性对话框中进行,更灵活地方式是在对话框类的 OnInitDialog()函数中进行控件的设置。默认情况下,OnInitDialog() 函数不出现在对话框类中,需要映射对话框类的 WM_INITDIALOG 窗口消息。下面继续修改应用程序 Exam6_1,实现功能:打开成绩录入对话框时, “确定”按钮不可用,当任意一个 Edit Box 的内容修改后, “确定”按钮可以使用。实现步骤如下:(1) 打开 ClassWizard 的 Member Variables 标签页,增加数据成员变量如表 6-2 所示。表 6-2 EX6 数据成员变量设置第 6 章 创建和使用对话框17控件
46、ID 变量名称 分类 数据类型IDC_SCORE1 m_Score1Edit control CEditIDC_SCORE2 m_Score2Edit control CEditIDC_SCORE3 m_Score3Edit control CEditIDC_SCORE4 m_Score4Edit control CEditIDC_SCORE5 m_Score5Edit control CEditIDOK m_OK control CButton(2) 打开 ClassWizard 的 Message Maps 标签页,Class name 中选择 CScoreDlg 类,Objects ID
47、s 中选择 CScoreDlg,Messages 中选择 WM_INITDIALOG 窗口消息,单击 Add Function 按钮。在对话框类 CScoreDlg 中增加了成员函数 OnInitDialog()。(3) 增加代码如程序清单 6-7 所示粗体部分。使对话框显示时, “确定”按钮灰色显示不能使用。 程序清单 6-7:初始化对话框函数示例BOOL CScoreDlg:OnInitDialog() CDialog:OnInitDialog();/ TODO: Add extra initialization herem_OK.EnableWindow (false);/禁止“确定”按
48、钮使用,灰色显示return TRUE; / return TRUE unless you set the focus to a control/ EXCEPTION: OCX Property Pages should return FALSE(4) 打开 ClassWizard 的 Message Maps 标签页,Class name 中选择 CScoreDlg,Object IDs 中选择IDC_SCORE1,Messages 中选择 EN_CHANGE 事件消息,单击 Add Function 按钮。对话框类CScoreDlg 增加对 Edit Box 进行修改事件的处理函数 OnC
49、hangeScore1()。(5) 在 OnChangeScore1()函数中添加代码如程序清单 6-8 所示粗体部分,使“确定”按钮可用。程序清单 6-8:EditBox 响应 EN_CHANGE 事件处理函数示例void CScoreDlg:OnChangeScore1() / TODO: Add your control notification handler code herem_OK.EnableWindow (true);(6) 重复(4)、(5)两步,为每一个 Edit Box 控件映射 EN_CHANGE 事件处理函数,并添加代码,使“确定”按钮可用。(7) 编译运行程序。6.4.3 无模式对话框无模式对话框与模式对话框的不同在于,用户打开无模式对话框后,仍然可以与其它用户界面交互。创建无模式对话框的过程与模式对话框基本相同,都包括对话框资源的创建和对话框的创建,但VC+6 简明教程18在运行对话框的设计上存在着差异:(1