第14单元对话框 第14单元对话框 教学目标 介绍对话框的概念和用法 学习要求 理解对话框、对话框模板和控件的概念,以及数据交换和验证机制,可编写使用对话框 的程序。 授课內容 对话框是一种特殊的窗口,主要功能是输岀信息和接收用户的输入。对话框与控件是密 不可分的,在每个对话框内一般都有一些控件,对话框依靠这些控件与用户进行交流信息 本单元主要介绍对话框,控件在第15单元中介绍 141对话框(Daog) 对话框( Dialog)实际上也是一个窗口。在MFC中,对话框的功能被封装在 CDialog 类中, CDialog类是CWnd类的派生类 对话框分为模态对话框和非模态对话框两种。模态对话框垄断了用户的输入,当一个模 态对话框打开时,用户只能与该对 话框进行交互,而其它用户界面对 是寻 1201 回团酬 象收不到用户的输入信息(如键盘口1nbng ]1201.cpt 和鼠标消息)。平时我们所遇到的量01 1201.ds 大部分对话框都是模态对话框,例国1201adb 如通过 File/Open命令打开的文件 打开@ 搜索对话框就是模态对话框(图文件型①匾 14-1)。非模态对话框类似普通的 窗口,并不垄断用户的输入。在非 图14-1文件搜索对话框 模式对话框打开时,用户随时可用 鼠标点击等手段激活其他窗口对象,操纵完毕后再回到本对话框。非模式对话框的典型例子 是 Microsoft word中的搜索对话框,打开搜索对话框后,用户仍可与其它窗口对象进行交互, 可以一边搜索,一边修改文章,非常方便
第 14 单元 对话框 275 第 14 单元 对话框 教学目标 介绍对话框的概念和用法。 学习要求 理解对话框、对话框模板和控件的概念,以及数据交换和验证机制,可编写使用对话框 的程序。 授课内容 对话框是一种特殊的窗口,主要功能是输出信息和接收用户的输入。对话框与控件是密 不可分的,在每个对话框内一般都有一些控件,对话框依靠这些控件与用户进行交流信息。 本单元主要介绍对话框,控件在第 15 单元中介绍。 14.1 对话框(Dialog) 对话框(Dialog)实际上也是一个窗口。在 MFC 中,对话框的功能被封装在 CDialog 类中,CDialog 类是 CWnd 类的派生类。 对话框分为模态对话框和非模态对话框两种。模态对话框垄断了用户的输入,当一个模 态对话框打开时,用户只能与该对 话框进行交互,而其它用户界面对 象收不到用户的输入信息(如键盘 和鼠标消息)。平时我们所遇到的 大部分对话框都是模态对话框,例 如通过 File/Open 命令打开的文件 搜索对话框就是模态对话框(图 14-1)。非模态对话框类似普通的 窗口,并不垄断用户的输入。在非 模式对话框打开时,用户随时可用 鼠标点击等手段激活其他窗口对象,操纵完毕后再回到本对话框。非模式对话框的典型例子 是 Microsoft Word 中的搜索对话框,打开搜索对话框后,用户仍可与其它窗口对象进行交互, 可以一边搜索,一边修改文章,非常方便。 图 14-1 文件搜索对话框
第14单元对话框 本节介绍模态对话框,非模态对话框将在145节介绍。 在程序中使用模态对话框有两个步骤: 1.在视图类或框架窗口类的消息响应函数(如鼠标消息或菜单选项的命令消息响应函 数)中说明一个对话框类的对象(变量) 2.调用 CDialog: DoModal()成员函数 DoModal()函数负责对模态话框的创建和撤销。在创建对话框时, DoModal()函数 的任务包括载入对话框模板资源、调用 OnInitDialog()函数初始化对话框和将对话框显示 在屏幕上。完成对话框的创建后, DoModal()函数启动一个消息循环,以响应用户的输入 由于该消息循环截获了几乎所有的输入消息,使主消息循环收不到对对话框的输入,致使用 户只能与模态对话框进行交互,而其它用户界面对象收不到输入信息。 如果用户在对话框内点击了标识符为IDOK的按钮(通常该按钮的标题是“确定”或 OK”),或者按了回车键,则 CDialog:: OnOK()函数会被调用。OnOK()函数首先调 用 UpdateData()函数将数据从控件传给对话框成员变量,然后调用 CDialog: Enddialog() 函数关闭对话框。关闭对话框后, DoModal()函数会返回值IDOK。 如果用户点击了标识符为 IDCANCEL的按钮(通常其标题为“取消”或“ Cancel”) 或按了ESC键,则会导致对 CDialog: On Cancel()函数的调用。该函数只调用 CDialog: Enddialog()函数关闭对话框。关闭对话框后, Do Modal()函数会返回 IDCANCELO 在应用程序中,可根据 DoModal()函数的返回值是IDOK还是 IDCANCEL来判断用 户是确定还是取消了对对话框的操作 从MFC编程的角度来看,一个对话框由两部分组成: 1.对话框模板资源:对话框模板用于指定对话框的形状、所用控件及其分布, Developer Studio根据对话框模板来创建对话框对象 2.对话框类:对话框类用来实现对话框的功能。由于各应用程序中的对话框具体功能 不同,因此一般要从 CDialog类中派生一个新类,以便添加特定的数据成员和成员函数。 相应地,对话框的设计也包括对话框模板的设计和对话框类的设计两个主要方面。具体 来说,应有以下步骤: 1.向项目中添加对话框模板资源; 2.编辑对话框模板资源,加入所需的控件 3.从 CDialog类派生对话框类,加入与各控件对应的数据成员 4.在框架窗口类或视图类的菜单选项、鼠标事件或其他消息响应函数中添加对话框对 象的应用代码。 向项目中添加对话框模板资源和编辑对话框模板资源的方法在14.7中介绍,下面主要 说明对话框类的设计方法,这包括以下几项工作: 1.从 CDialog类派生一个对话框类,并通过对话框模板资源的ID建立它们之间的对应 关系 2.为对话框类添加与各控件相对应的成员变量
第 14 单元 对话框 276 本节介绍模态对话框,非模态对话框将在 14.5 节介绍。 在程序中使用模态对话框有两个步骤: 1.在视图类或框架窗口类的消息响应函数(如鼠标消息或菜单选项的命令消息响应函 数)中说明一个对话框类的对象(变量); 2.调用 CDialog::DoModal()成员函数。 DoModal()函数负责对模态话框的创建和撤销。在创建对话框时,DoModal()函数 的任务包括载入对话框模板资源、调用 OnInitDialog()函数初始化对话框和将对话框显示 在屏幕上。完成对话框的创建后,DoModal()函数启动一个消息循环,以响应用户的输入。 由于该消息循环截获了几乎所有的输入消息,使主消息循环收不到对对话框的输入,致使用 户只能与模态对话框进行交互,而其它用户界面对象收不到输入信息。 如果用户在对话框内点击了标识符为 IDOK 的按钮(通常该按钮的标题是“确定”或 “OK”),或者按了回车键,则 CDialog::OnOK()函数会被调用。OnOK()函数首先调 用 UpdateData()函数将数据从控件传给对话框成员变量,然后调用 CDialog::EndDialog() 函数关闭对话框。关闭对话框后,DoModal()函数会返回值 IDOK。 如果用户点击了标识符为 IDCANCEL 的按钮(通常其标题为“取消”或“Cancel”), 或按了 ESC 键, 则会导 致对 CDialog::OnCancel( )函数 的调 用。该 函数 只调用 CDialog::EndDialog()函数关闭对话框。关闭对话框后,DoModal()函数会返回 IDCANCEL。 在应用程序中,可根据 DoModal()函数的返回值是 IDOK 还是 IDCANCEL 来判断用 户是确定还是取消了对对话框的操作。 从 MFC 编程的角度来看,一个对话框由两部分组成: 1.对话框模板资源:对话框模板用于指定对话框的形状、所用控件及其分布,Developer Studio 根据对话框模板来创建对话框对象。 2.对话框类:对话框类用来实现对话框的功能。由于各应用程序中的对话框具体功能 不同,因此一般要从 CDialog 类中派生一个新类,以便添加特定的数据成员和成员函数。 相应地,对话框的设计也包括对话框模板的设计和对话框类的设计两个主要方面。具体 来说,应有以下步骤: 1.向项目中添加对话框模板资源; 2.编辑对话框模板资源,加入所需的控件; 3.从 CDialog 类派生对话框类,加入与各控件对应的数据成员; 4.在框架窗口类或视图类的菜单选项、鼠标事件或其他消息响应函数中添加对话框对 象的应用代码。 向项目中添加对话框模板资源和编辑对话框模板资源的方法在 14.7 中介绍,下面主要 说明对话框类的设计方法,这包括以下几项工作: 1.从 CDialog 类派生一个对话框类,并通过对话框模板资源的 ID 建立它们之间的对应 关系; 2.为对话框类添加与各控件相对应的成员变量;
第14单元对话框 3.为对话框进行初始化工作; 4.增加对控件通知消息的处理 例141为例9-1的吹泡泡程序加一版权( About)对话框 说明: Windows应用程序大都有一版权对话框,提供软件的版本号、出品商和版 权说明等信息。版权对國 区 话框可以通过主菜单上「MM习● 的“关于.”菜单选项 的③回日萬2·g,国曾%四 d msEX: Fol 调出,也可以通过鼠标 E IDD DIALOGI 右键调出。本例采用后 吹泡泡程序 Version10 一种方法。 Copyright 2000 首先建立Win32 四安交通大学计机教学实验中心 Application空项目,为 项目建立C++ Source ral Styles I Extended Styles I esource Caption:计算机数芋买验中心 文件(建立后关闭) F Visible F Group Disabled「 Tab stop 并将项目设置为使用 MFC 向项目中添加一个 图14-2编辑吹泡泡程序的版权对话框 对话框模板资源(通过 菜单选项 Insert/ Resource.),将其 Caption改为“关于吹泡泡程序”。然后利用对话框编 辑器添加3个静态文本控件( Static Text)说明版本信息并删除“ Cancel”按钮,见图14-2 然后修改例9-1的程序,加入以下内容: 程序 1.在程序首部加上文件包含命令 # include“ resource.h 2.在框架窗口类之前加入从 CDialog类派生的对话框类: /对话框类 class CAboutDlg: public CDialog CAboutDlgo enum [IDD= IDD DIALOG1] inline CAboutDlg: CAboutDlg(: CDialog(CAboutDlg:: IDD) 3.在框架窗口类中添加响应鼠标右键消息的代码,包括消息响应函数说明、消息响应 宏和消息响应函数定义。鼠标右键消息响应函数为
第 14 单元 对话框 277 3.为对话框进行初始化工作; 4.增加对控件通知消息的处理。 [例 14-1] 为例 9-1 的吹泡泡程序加一版权(About)对话框。 说 明:Windows 应用程序大都有一版权对话框,提供软件的版本号、出品商和版 权说明等信息。版权对 话框可以通过主菜单上 的“关于… ”菜单选项 调出,也可以通过鼠标 右键调出。本例采用后 一种方法。 首先建立 Win32 Application 空项目,为 项目建立 C++ Source File 和 Resource Script 文件(建立后关闭), 并将项目设 置为使用 MFC。 向项目中添加一个 对话框模板资源(通过 菜单选项 Insert/Resource…),将其 Caption 改为“关于吹泡泡程序”。然后利用对话框编 辑器添加 3 个静态文本控件(Static Text)说明版本信息并删除“Cancel”按钮,见图 14-2。 然后修改例 9-1 的程序,加入以下内容: 程 序: 1.在程序首部加上文件包含命令 #include “resource.h” 2.在框架窗口类之前加入从 CDialog 类派生的对话框类: // 对话框类 class CAboutDlg: public CDialog { public: CAboutDlg(); enum {IDD = IDD_DIALOG1}; }; inline CAboutDlg::CAboutDlg():CDialog(CAboutDlg::IDD){} 3.在框架窗口类中添加响应鼠标右键消息的代码,包括消息响应函数说明、消息响应 宏和消息响应函数定义。鼠标右键消息响应函数为: 图 14-2 编辑吹泡泡程序的版权对话框
第14单元对话框 void CMyWnd: OnRBut tonDown (UINT nFlags, CPoint point) CAboutDig dl dlg DoModal O 输入输出:除可用鼠标左键生成泡泡外,按下鼠标右键会弹出一版权对话框 分析:该对话框仅提供了固定的版本信息,没有实现用户与应用程序间的数据交流 所以结构比较简单。 CAboutDIg类重载了构造函数并调用了基类 CDialog的构造函数来实现 对话框模板资源和对话框类之间的关联。注意其中的枚举类型定义,其实质是将具体的对话 框模板资源的标识符在对话框类内映射为统一的标识符IDD 在框架窗口类的 OnR Button Down()成员函数中,声明了一个 CAboutDIg类的对象 并通过其 DoModal()成员函数调用该对话框。这是典型的模态对话框调用方法,除非用 户按下对话框上的OK按钮、 Cancel()按钮或窗口右上角的关闭按钮退出对话框,用户的 所有输入信息均被该对话框截留(无论该信息对对话框是否有用) 实际上,可以使用 Class wizard直接从对话框模板资源生成对应的对话框类代码,无需 手工编程。这方面的内容请参看148:“使用 ClassWizard建立对话框类”。 142控件 要使对话框真正具有与用户对话的能力,还必须使用控件。所谓控件,就是一个现成的 程序组件,可以独立运行以完成一定的功能。 Windows提供了大量控件,控件的使用不仅方 便了 Windows编程,还使 Windows程序具有相当统一的外观和风格。 控件多与对话框一起使用。所有的控件都是CWnd类派生出来的后代类对象,因此它 们均有和CWnd类似的属性。每个控件均有一个标识符(ID),在程序中可以通过这个标识 符对相应的控件进行操作 使用 Visual c++编程时可用的控件很多,在本单元中,仅介绍其中的两个:静态文本控 件和编辑控件,目的是介绍对话框中的数据交换机制。第15单元集中介绍其他控件。 静态文本控件是最简单的控件,其用途是在对话框上显示一段文字。在例14-1中,就 是使用静态文本控件来显示软件的版本信息的。由于静态文本控件的文字和属性均在编辑对 话框模板资源时确定,程序运行中一般无法改变,所以在编程时无需考虑静态文本控件 编辑控件是最有用的控件,其功能十分全面,本身就是一个小型的文本编辑器。编辑控 件的作用是接受用户输入的字符串信息。 以上控件作为资源的编辑方法可参看147:“对话框模板资源的编辑”。 143对话框的初始化 对话框的初始化工作一般在构造函数和 OnInitDialog()函数中完成。在构造函数中的 初始化工作主要是针对对话框的数据成员进行的
第 14 单元 对话框 278 void CMyWnd::OnRButtonDown(UINT nFlags, CPoint point) { CAboutDlg dlg; dlg.DoModal(); } 输入输出:除可用鼠标左键生成泡泡外,按下鼠标右键会弹出一版权对话框。 分 析:该对话框仅提供了固定的版本信息,没有实现用户与应用程序间的数据交流, 所以结构比较简单。CAboutDlg 类重载了构造函数并调用了基类 CDialog 的构造函数来实现 对话框模板资源和对话框类之间的关联。注意其中的枚举类型定义,其实质是将具体的对话 框模板资源的标识符在对话框类内映射为统一的标识符 IDD。 在框架窗口类的 OnRButtonDown()成员函数中,声明了一个 CAboutDlg 类的对象, 并通过其 DoModal()成员函数调用该对话框。这是典型的模态对话框调用方法,除非用 户按下对话框上的 OK 按钮、Cancel()按钮或窗口右上角的关闭按钮退出对话框,用户的 所有输入信息均被该对话框截留(无论该信息对对话框是否有用)。 实际上,可以使用 ClassWizard 直接从对话框模板资源生成对应的对话框类代码,无需 手工编程。这方面的内容请参看 14.8:“使用 ClassWizard 建立对话框类”。 14.2 控件 要使对话框真正具有与用户对话的能力,还必须使用控件。所谓控件,就是一个现成的 程序组件,可以独立运行以完成一定的功能。Windows 提供了大量控件,控件的使用不仅方 便了 Windows 编程,还使 Windows 程序具有相当统一的外观和风格。 控件多与对话框一起使用。所有的控件都是 CWnd 类派生出来的后代类对象,因此它 们均有和 CWnd 类似的属性。每个控件均有一个标识符(ID),在程序中可以通过这个标识 符对相应的控件进行操作。 使用 Visual C++编程时可用的控件很多,在本单元中,仅介绍其中的两个:静态文本控 件和编辑控件,目的是介绍对话框中的数据交换机制。第 15 单元集中介绍其他控件。 静态文本控件是最简单的控件,其用途是在对话框上显示一段文字。在例 14-1 中,就 是使用静态文本控件来显示软件的版本信息的。由于静态文本控件的文字和属性均在编辑对 话框模板资源时确定,程序运行中一般无法改变,所以在编程时无需考虑静态文本控件。 编辑控件是最有用的控件,其功能十分全面,本身就是一个小型的文本编辑器。编辑控 件的作用是接受用户输入的字符串信息。 以上控件作为资源的编辑方法可参看 14.7:“对话框模板资源的编辑”。 14.3 对话框的初始化 对话框的初始化工作一般在构造函数和 OnInitDialog()函数中完成。在构造函数中的 初始化工作主要是针对对话框的数据成员进行的
第14单元对话框 在对话框创建时,会收到 WM INITDIALOG消息,对话框对该消息的处理函数是 OnInitDialog()。调用 OnInitdialog()函数时,对话框已初步创建,对话框的窗口句柄也 已有效,但对话框还未被显示出来。因此,可以在 OnlnitDialog()函数中做一些影响对话 框外观的初始化工作。 OnInitDialog()对对话框类的作用与 On create)函数对 MAin Frame 类的作用类似。 144对话框的数据交换和数据检验机制 在程序中,通过控件与用户的数据交流是分两步完成的。首先,要在对话框类中加入与 控件对应的数据成员,通过数据交换(DDX)确定其与控件的数据交换关系。例如对于编 辑控件,可在对话框类中声明一个 CString类的数据成员,并通过DDX将其与编辑控件联 系起来。这样,打开对话框时,编辑控件窗口显示的就是该数据成员原来的值,如果用户对 编辑控件的内容进行了编辑修改,则在退出对话框后,该数据成员的值也相应地变为编辑后 的内容。 在视图类(或框架窗口类)中调用对话框时,还可通过对话框的数据成员来处理用户的 输入数据。具体说来,在调用对话框类的 DoModal()函数打开对话框之前,可以通过设 置对话框数据成员的值,使其成为控件窗口的显示信息:在退出对话框后,又可将对话框数 据成员所反映的用户输入数据应用到程序的其他部分。也正因为如此,对话框类的数据成员 通常被说明为 public的,以便在上述情况下直接处理。 MFC提供了 DAtaeXchange类来实现对话框类与控件之间的数据交换(DDX),该类 还提供了数据检验机制(DDV)。所谓数据检验,即对用户输入数据的范围进行检査,如 果不符合要求则拒绝接受。这样可以将用户输入数据限制在一预先确定的范围内。数据交换 和检验机制不仅适用于编辑框控件,还适用于检査框、单选按钮、列表框和组合框等控件。 数据交换和检验机制通过 CDialog: DoDataExchange()函数来完成,其原型为 virtual void DoData Exchange( CDataExchange* pDX ) 其中参数pDX为指向 DAtaeXchange类对象的指针,框架使用该对象建立数据交换内 容。该函数由程序控件直接调用,可重载以加入数据交换函数实现对话框数据成员与控件的 联系。数据交换函数很多,这里先介绍与编辑控件有关的数据交换函数 void DDX Text( CDataExchange* pDX, int nlDC, int& value ) void DDX Text( CDataExchange* pDX, int nlDC, long& value yoid DDX Text( CDataExchange* pDX, int nlDC, CString& value ) void DDX Text( CDataExchange* pDX, int nlDC, float& value void DDX Text( CDataExchange* pDX, int nlDC, double& value ) 其中参数pDX是指向 DAtaeXchange对象的指针;参数nDC是对话框对象中的编辑控件 的标识符:而参数 value是对话框中的数据成员的引用。注意该参数的类型不仅可以是 CString,而且可以是各种数值类型。因此,编辑控件不仅可以用来输入文字数据,也可以 用来输入数值数据
第 14 单元 对话框 279 在对话框创建时,会收到 WM_INITDIALOG 消息,对话框对该消息的处理函数是 OnInitDialog()。调用 OnInitDialog()函数时,对话框已初步创建,对话框的窗口句柄也 已有效,但对话框还未被显示出来。因此,可以在 OnInitDialog()函数中做一些影响对话 框外观的初始化工作。OnInitDialog()对对话框类的作用与 OnCreate()函数对 CMainFrame 类的作用类似。 14.4 对话框的数据交换和数据检验机制 在程序中,通过控件与用户的数据交流是分两步完成的。首先,要在对话框类中加入与 控件对应的数据成员,通过数据交换(DDX)确定其与控件的数据交换关系。例如对于编 辑控件,可在对话框类中声明一个 CString 类的数据成员,并通过 DDX 将其与编辑控件联 系起来。这样,打开对话框时,编辑控件窗口显示的就是该数据成员原来的值,如果用户对 编辑控件的内容进行了编辑修改,则在退出对话框后,该数据成员的值也相应地变为编辑后 的内容。 在视图类(或框架窗口类)中调用对话框时,还可通过对话框的数据成员来处理用户的 输入数据。具体说来,在调用对话框类的 DoModal()函数打开对话框之前,可以通过设 置对话框数据成员的值,使其成为控件窗口的显示信息;在退出对话框后,又可将对话框数 据成员所反映的用户输入数据应用到程序的其他部分。也正因为如此,对话框类的数据成员 通常被说明为 public 的,以便在上述情况下直接处理。 MFC 提供了 CDataExchange 类来实现对话框类与控件之间的数据交换(DDX),该类 还提供了数据检验机制(DDV)。所谓数据检验,即对用户输入数据的范围进行检查,如 果不符合要求则拒绝接受。这样可以将用户输入数据限制在一预先确定的范围内。数据交换 和检验机制不仅适用于编辑框控件,还适用于检查框、单选按钮、列表框和组合框等控件。 数据交换和检验机制通过 CDialog::DoDataExchange()函数来完成,其原型为: virtual void DoDataExchange ( CDataExchange* pDX ); 其中参数 pDX 为指向 CDataExchange 类对象的指针,框架使用该对象建立数据交换内 容。该函数由程序控件直接调用,可重载以加入数据交换函数实现对话框数据成员与控件的 联系。数据交换函数很多,这里先介绍与编辑控件有关的数据交换函数: void DDX_Text ( CDataExchange* pDX, int nIDC, int& value ); void DDX_Text ( CDataExchange* pDX, int nIDC, long& value ); void DDX_Text ( CDataExchange* pDX, int nIDC, CString& value ); void DDX_Text ( CDataExchange* pDX, int nIDC, float& value ); void DDX_Text ( CDataExchange* pDX, int nIDC, double& value ); 其中参数 pDX 是指向 CDataExchange 对象的指针;参数 nIDC 是对话框对象中的编辑控件 的标识符;而参数 value 是对话框中的数据成员的引用。注意该参数的类型不仅可以是 CString,而且可以是各种数值类型。因此,编辑控件不仅可以用来输入文字数据,也可以 用来输入数值数据