Download presentation
Presentation is loading. Please wait.
1
第4章 对话框和常用控件 对话框是Windows应用程序中最重要的用户界面元素之一,是与用户交互的重要
第4章 对话框和常用控件 对话框是Windows应用程序中最重要的用户界面元素之一,是与用户交互的重要 手段。在程序运行过程中,对话框可用于捕捉用户的输入信息或数据。对话框是 一个特殊类型的窗口,任何对窗口进行的操作(如移动、最大化、最小化等)也可 在对话框中实施。一般来说,在对话框中通过各种控件(如按钮、编辑框、列表 框、组合框等)来和用户进行交互,控件是在系统内部定义的用于和用户交互的 基本单元。 4.1 对话框的使用 在Visual C++ 6.0应用程序中,使用一个对话框的一般过程是:①添加对话框资 源;②设置对话框的属性;③添加和布局控件;④创建对话框类;⑤添加对话框 代码;⑥在程序中调用对话框。
2
4.1.1 资源与资源标识 1. 资源的分类 先用MFC AppWizard创建一个单文档应用程序Ex_SDI,然后项目工作区窗口切换到“ResourceView”页面,展开所有的节点,如图4.1所示。 图4.1 Ex_SDI资源视图 资源类别 资源标识符
3
1. 资源的分类 可以看出,一个单文档应用程序所使用的资源可分为下列几类:
(1) 快捷键列表(Accelerator)。一系列组合键的集合,被应用程序用来引发一个 动作。该列表一般与菜单命令相关联,用来代替鼠标操作。 (2) 对话框(Dialog)。含有按钮、列表框、编辑框等各种控件的窗口。 (3) 图标(Icon)。代表应用程序显示在Windows桌面上的位图,它同时有32x32像 素和16x16像素两种规格。 (4) 菜单(Menu)。用户通过菜单可以完成应用程序的大部分操作。 (5) 字串表(String Table)。应用程序使用的全局字符串或其他标识符。 (6) 工具栏按钮(Toolbar)。工具栏外观是以一系列具有相同尺寸的位图组成的, 它通常与一些菜单命令相对应,用以提高用户的工作效率。 (7) 版本信息(Version)。包含应用程序的版本、用户注册码等相关信息。 除了上述常用资源类别外,Visual C++ 6.0应用程序中还可有鼠标指针、HTML 等,也可以自己添加新的资源类别。
4
4.1.1 资源与资源标识 2. ID标识符 一般地,要遵循下列规则: 在标识符名称中允许使用字母a~z、A~Z、0~9以及下划线。
标识符名称不区分大小写字母,如new_idd与New_Idd是相同的标识符。 不能以数字开头,如8BIT是不合法的标识符名。 除了上述规则外,出于习惯,Visual C++还提供了一些常用的定义标识符名称的前缀供用 户使用、参考,见表4.1。
5
4.1.2 添加对话框资源 在一个MFC应用程序中添加对话框资源,通常按下列步骤进行:
(1) 选择“插入”→“资源”菜单,或按快捷键Ctrl+R打开“插入资源”对话框,在对话框中 可以看到资源列表中存在Dialog项,若单击Dialog项左边的“+”号,将展开对话框资源 的不同类型选项,如图4.2所示,表4.2列出各种类型的对话框资源的不同用途。 图4.2 “插入资源”对话框
6
4.1.2 添加对话框资源 其中,[新建]按钮是用来创建一个由“资源类型”列表中指定类型的新资源,[定制]按钮是用来创建“资源类型”列表中没有的新类型的资源,[导入]按钮是用于将外部已有的位图、图标、光标或其他定制的资源添加到当前应用程序中。 表4.2 对话框资源类型
7
4.1.2 添加对话框资源 (2) 对展开的不同类型的对话框资源不作任何选择,选中“Dialog”,单击[新建]按
钮,系统就会自动为当前应用程序添加了一个对话框资源,并出现如图4.3所示 的界面。 对话框模板 控件工具栏 布局工具栏 默认标识符 图4.3 添加对话框资源后的开发环境
8
4.1.3 设置对话框属性 在对话框模板处右击鼠标,从弹出的快捷菜单中选择“属性”菜单项,出现如图4.4 所示的对话框属性窗口。
图4.4 对话框属性窗口
9
4.1.3 设置对话框属性 可以看出,对话框的属性有General(一般)、Styles(风格)、More Styles(更多风
格)、Extended Styles(扩展风格)、More Extended Styles(更多扩展风格)等部 分,这里仅介绍最常用的General属性,如表4.3所示。 表4.3 对话框的General属性
10
4.1.3 设置对话框属性 将添加的对话框的属性进行以下3点修改,结果如图4.5所示:
● 将对话框标识符改成IDD_DIALOG_FIRST; ● 将对话框标题改为“我的第一个对话框”; ● 单击[字体]按钮,通过弹出的字体对话框将对话框内的文本设置成“宋体,9” ,以使自己 的对话框和Windows中的对话框保持外观上的一致。 图4.5 对话框属性修改后的界面
11
4.1.4 添加和布局控件 一旦对话框资源被打开或被创建,就会出现对话框编辑器,通过它可以在对话框中进行控 件的添加和布局等操作。
1. 控件的添加 对话框编辑器最初打开时,控件工具栏是随之出现的,利用此工具栏中的各个按钮可以顺 利完成控件的添加。图4.6说明了各个按钮所对应的控件类型。 控件的选择 静态文本 组框 复选框 组合框 水平滚动条 旋转按钮 滑动条 列表视图 标签 复合编辑 月历 用户定制控件 静态图片 编辑框 按钮 单选框 列表框 垂直滚动条 进展条 热键 树形视图 动画 日期选择 IP地址 扩展组合框 图4.6 控件工具栏和各按钮含义
12
4.1.4 添加和布局控件 在对话框中添加一个控件的方法有下列几种:
● 在控件工具栏中单击某控件,此时的鼠标箭头在对话框内变成“十”字形状;在 对话框指定位置单击鼠标左键,则此控件被添加到对话框的相应位置,再拖动刚 添加控件的选择框可改变其大小和位置。 ● 在控件工具栏中单击某控件,此时的鼠标箭头对话框内变成“十”字形状;在指 定位置处单击鼠标左键不放,拖动鼠标至满意位置,释放鼠标键。 ● 用鼠标左键点中控件工具栏中的某控件,并按住鼠标左键不放;在移动鼠标到 对话框的指定位置的过程中,用户会看到一个虚线框,下面带有该控件的标记; 释放鼠标左键,新添加的控件立即出现在对话框中。
13
4.1.4 添加和布局控件 2. 控件的选取 控件的删除、复制和布局操作一般都要先选取控件,若选取单个控件,则可以下 列方法:
● 用鼠标直接选取。首先保证在控件工具栏中的选择按钮()是被选中的,然后移 动鼠标指针至指定的控件上,单击鼠标左键即可。 ● 用助记符来选取。如果控件的标题中带有下划线的字符,这个字符就是助记 符,选择时直接按下该助记符键或“Alt+助记符”组合键即可。 ● 用Tab键选取。在对话框编辑器中,系统会根据控件的添加次序自动设置相应 的Tab键次序。利用Tab键,用户可在对话框内的控件中进行选择。每按一次Tab 键依次选取对话框中的下一个控件,若按住Shift键,再单击Tab键则选取上一个 控件。 对于多个控件的选取,可采用下列方法: ● 先在对话框内按住鼠标左键不放,拖出一个大的虚框,然后释放鼠标,则被该 虚框所包围的控件都将被选取。 ● 先按住Shift键不放,然后用鼠标选取控件,直到所需要的多个控件选取之后再 释放Shift键。若在选取时,对已选取的控件再选取一下,则取消该控件选取。
14
4.1.4 添加和布局控件 需要注意的是: (1) 一旦单个控件被选取后,其四周由选择框包围着,选择框上还有几个(通常是
八个)蓝色实心小方块,拖动它可改变控件的大小,如图4.7(a)所示。 (2) 多个控件被选取后,其中只有一个控件的选择框有几个蓝色实心小方块,这 个控件称为主要控件,而其他控件的选择框的小方块是空心的。如图4.7(b)所示。 图4.7 单个控件和多个控件的选择框 (a) (b)
15
4.1.4 添加和布局控件 3. 控件的删除、复制和布局 当单个控件或多个控件被选取后,按方向键或用鼠标拖动控件的选择框可移动控
件。若在鼠标拖动过程中还按住Ctrl键则复制控件。若按Del键可将选取的控件删 除。当然还有其他一些编辑操作,但这些操作方法和一般的文档编辑器基本相 同,这里不再重复。 对于控件的布局,对话框编辑器中提供了控件布局工具栏,如图4.8所示,它可 以自动地排列对话框内的控件,并能改变控件的大小。 图4.8 控件布局工具栏
16
3. 控件的删除、复制和布局 与布局工具相对应的菜单命令在“编排”菜单下,而且大部分命令均有相应的快捷
键,如图4.9所示。表4.4还列出菜单命令及其相应的功能与快捷键描述。“编排” 菜单不是在Visual C++ 6.0开发环境一开始就出现的,而是随着对话框编辑器的 打开而显示的。 表4.4 “编排”菜单命令的快捷键及功能描述 图4.9 “编排”菜单命令项
17
4.1.4 添加和布局控件 4. 测试对话框 “编排”菜单下的Test命令或布局工具栏上的测试按钮是用来模拟所编辑的对话框的运行情
况,帮助用户检验对话框是否符合用户的设计要求以及控件功能是否有效等。 5. 操作示例 下面来向对话框添加一个静态文本控件。一个静态文本控件就是一个文本标签,如图4.10 所示。右击添加的控件,从弹出的快捷菜单中选择“属性”,出现如图4.11所示的属性对话 框。 图4.11 静态文本控件的属性对话框 图4.10 添加的静态文本控件
18
4.1.5 创建对话框类 在对话框资源模板的空白区域(没有其他元素或控件)内双击鼠标,将弹出如图
4.12所示的对话框,询问是否为对话框资源创建一个新类。 单击[OK]按钮,将弹出如图4.13所示的New Class对话框。在Name框中输入类 名CFirstDlg。Base class和Dialog ID内容是由系统自动设置的,一般无需修改。 从Base class框的内容可以看出,用户对话框类是从基类CDialog派生而来的。 单击[OK]按钮,一个基于对话框资源模板的对话框类CFirstDlg就创建好了。此 时,出现MFC ClassWizard(MFC类向导)对话框。 图4.12 “Adding a Class”对话框 图4.13 “New Class”对话框
19
图4.14 “MFC ClassWizard”对话框
4.1.6 添加对话框代码 在MFC ClassWizard对话框,查看“Class name”列表中是否选择了CFirstDlg,若 不是,则在IDs列表中选择CFirstDlg。 在Messages框中找到并选定WM_INITDIALOG消息,如图4.14。 图4.14 “MFC ClassWizard”对话框
20
4.1.6 添加对话框代码 在Member functions列表框中选择刚添加的OnInitDialog函数,单击[Edit Code]按钮(或 直接在函数名双击鼠标),将自动出现该函数代码编辑窗口,在此函数中添加下列代码: BOOL CFirstDlg::OnInitDialog() { CDialog::OnInitDialog(); // TODO: Add extra initialization here CStatic* pWnd = (CStatic*)GetDlgItem(IDC_STATIC_1); pWnd->SetWindowText("这是我的第一个对话框!"); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } 代码中,CStatic是静态文本控件的MFC类,SetWindowText是CWnd的一个成员函数, 用来设置窗口的文本内容,由于控件类是CWnd的子类(派生类),因此可以使用基类的 SetWindowText来改变静态文本控件显示的内容。GetDlgItem也是CWnd类的一个成员 函数,用来获得对话框中控件(参数是控件的ID标识符,这里是IDC_STATIC_1)的窗口 指针。
21
4.1.7 在程序中调用对话框 在项目工作区窗口中选择ResourceView页面,双击资源“Menu”项中的
IDR_MAINFRAME,则菜单编辑器窗口出现在主界面的右边,相应的Ex_SDI项目的菜单 资源被显示出来,在菜单的最右一项,Visual C++为用户留出了一个空位置,用来输入新 的菜单项,如图4.15所示。 菜单的空位置 图4.15 Ex_SDI菜单资源
22
4.1.7 在程序中调用对话框 (2) 在菜单的空位置上双击鼠标左键,则出现它的属性对话框,在标题框中输入“测试
(&T)”,结果如图4.16所示,其中符号&用来其后面的字符作为该菜单项的助记符,这样当 按住“Alt”键不放,再敲击该助记符键时,对应的菜单项就会被选中,或在菜单打开时,直 接按相应的助记符键,对应的菜单项也会被选中。 子菜单的空位置 保存可见按钮 图4.16 Ex_SDI菜单资源
23
4.1.7 在程序中调用对话框 (3) 单击菜单属性对话框中的“保存可见”(Keep Visible)按钮,使此属性对话框一
直可见。单击“测试”菜单项下方的空位置,在属性对话框中,输入标题“对话框 (&D)”,在ID框输入该菜单项的资源标识:ID_TEST_DLG,结果如图4.17所示, 单击属性对话框右上角的关闭按钮。 (4) 单击“测试”菜单项并按住鼠标左键不放,移动鼠标,将“测试”菜单项移到“查 看”和“帮助”菜单项之间,然后释放鼠标。结果如图4.18所示。 图4.17 修改菜单项属性 图4.18 菜单项“对话框”拖放后的位置
24
4.1.7 在程序中调用对话框 (5) 按Ctrl+W快捷键,弹出MFC ClassWizard对话框。在Message Maps页面
中,从Class name列表中选择CMainFrame,在IDs列表中选择ID_TEST_DLG, 然后在Messages框中选择COMMAND消息。 (6) 单击[Add Function]按钮或双击COMMAND消息,出现Add Member Function 对话框,输入成员函数的名称。系统默认的函数名为OnTestDlg,如图4.19所 示。该函数是对菜单项ID_TEST_DLG的映射,也就是说,当在应用程序运行 时,用户选择“测试”→“对话框”,则该函数OnTestDlg被调用,执行函数中的代 码。 图4.19 添加成员函数
25
4.1.7 在程序中调用对话框 (7) 单击[OK]按钮,在ClassWizard的Member functions列表中将列出新增加的成
员函数。选择此函数,单击[Edit Code]按钮(或直接双击函数名),在此成员函数 中添加下列代码: void CMainFrame::OnTestDlg() { CFirstDlg dlg; // 定义对话框类对象 dlg.DoModal(); // 显示对话框 } 代码中,DoModal是CDialog基类成员函数,用来将对话框按模式方式来显示。 (8) 在OnTestDlg函数的实现文件MainFrm.cpp的前面添加CFirstDlg类的包含语 句,即: #include "Ex_SDI.h" #include "MainFrm.h" #include "FirstDlg.h"
26
4.1.7 在程序中调用对话框 (9) 编译并运行。在应用程序菜单上,选择“测试”→“对话框”菜单项,将出现如图
4.20的对话框,这个对话框就是刚才添加的对话框。 图4.20 对话框的显示
27
4.1.8 使用无模式对话框 对话框有两种类型,一种是模式对话框,另一是无模式对话框。 1. 模式对话框
所谓“模式对话框”是指当对话框被弹出,用户必须在对话框中作出相应的操作, 在退出对话框之前,对话框所在应用程序的其它操作不能继续执行。 一般情况下,模式对话框会有[OK](确定)和[Cancel](取消)按钮。单出[OK]按钮, 系统认定用户在对话框中的选择或输入有效,对话框退出;单击[Cancel]按钮, 对话框中的选择或输入无效,对话框退出,程序恢复原有状态。 模式对话框的应用范围较广,上面示例中的对话框和平常所见到的大多数对话框 都是模式对话框。 2. 无模式对话框 所谓“无模式对话框”是指当对话框被弹出后,一直保留在屏幕上,用户可继续在 对话框所在的应用程序中进行其它操作;当需要使用对话框时,只需象激活一般 窗口一样单击对话框所在的区域即可激活。
28
4.1.8 使用无模式对话框 下面在单文档应用程序Ex_SDI中创建并使用无模式对话框,其步骤如下:
(1) 在该项目中添加一个对话框资源,将其标识符设为IDD_DIALOG_SECOND, 标题设为“无模式对话框”,对话框字体和大小设为“宋体,9号”。 (2) 为IDD_DIALOG_SECOND对话框资源创建一个对话框类CSecondDlg。 (3) 按Ctrl+W快捷键打开MFC ClassWizard,从“Class name”列表中选择 CSecondDlg,在IDs列表中选择IDOK,它是对话框中[OK]按钮的标识符,然后 在Messages框中选择BN_CLICKED(单击按钮)消息,单击[Add Function]按钮或 双击BN_CLICKED消息,出现“Add Member Function”对话框以输入成员函数的 名称,保留系统默认的函数名为OnOK,如图4.21所示。该函数是对[OK]按钮单 击消息的映射,即当用户单击此对话框中的[OK]按钮时,OnOK函数被执行。 (4) 修改CSecondDlg::OnOK函数中的代码。 void CSecondDlg::OnOK() { DestroyWindow(); // 终止对话框显示 delete this; // 删除对话框,释放内存空间 } 代码中,DestroyWindow是对话框基类CWnd的一个成员函数,用来终止窗口。
29
图4.21 映射IDOK消息
30
4.1.8 使用无模式对话框 (5) 用MFC ClassWizard来添加[Cancel]按钮(标识符为IDCANCEL)的BN_CLICKED消 息映射,并修改其映射函数CSecondDlg::OnCancel的代码。 void CSecondDlg::OnCancel() { DestroyWindow(); delete this; } (6) 将项目工作区切换到ClassView(类视图)页面,展开CMainFrame类的所有成员, 双击OnTestDlg就会在文档窗口中自动定位到该函数的实现代码处,将其修改成下列 代码: void CMainFrame::OnTestDlg() CSecondDlg *pDlg = new CSecondDlg; // 使用new来为对话框分配内存空间 pDlg->Create( IDD_DIALOG_SECOND ); // 创建对话框 pDlg->ShowWindow( SW_NORMAL ); // 显示对话框 代码中,Create函数可以用来以一个对话框资源来创建对话框,ShowWindow是 CWnd一个成员函数,用来显示对话框,SW_NORMAL用来指定将窗口显示成一般常 用的状态。
31
4.1.8 使用无模式对话框 (7) 在文件MainFrm.cpp的前面添加CSecondDlg类的包含语句,即:
#include "FirstDlg.h" #include "SecondDlg.h" (8) 编译并运行。在应用程序菜单上,多次选择“测试”→“对话框”菜单项,将会在 同一个位置中出现多个对话框,拖动这些对话框到适当位置,如图4.22所示。 图4.22 无模式对话框显示的结
32
4.2 控件的创建和使用方法 控件是在系统内部定义的能够完成特定功能的控制程序单元。在应用程序中使用
控件不仅简化了编程,还能完成常用的各种功能。为了更好地发挥控件作用,用 户还必须理解和掌握控件的属性、消息以及创建和使用的方法。 4.2.1 控件的创建方法 控件的创建方式有以下两种:一种是在对话框模板中用编辑器指定控件,也就是 说,将控件的父窗口指定为对话框,这样做的好处是明显的,因为当应用程序启 动该对话框时,Windows系统就会为对话框创建控件;而当对话框消失时,控件 也随之清除。另一种方式是将控件看作是任一窗口的子窗口,并通过调用相应的 Create函数来创建。
33
4.2.1 控件的创建方法 [例Ex_DlgCtrls] 使用控件的编程方式来创建一个按钮
(1) 选择“文件”→“新建”菜单,在弹出的新建对话框的项目类型列表中选择MFC AppWizard(exe)类型,在工程框中输入项目名Ex_DlgCtrls,结果如图4.23所示。 图4.23 MFC AppWizard的“新建”对话框
34
4.2.1 控件的创建方法 (2) 单击[确定]按钮,在出现的“Step 1”对话框中选择“基本对话”应用程序类型,
单击[完成]按钮,创建一个默认的基于对话框的应用程序项目。 (3) 将项目工作区切换到ClassView页面,展开CEx_DlgCtrlsDlg类,右击 CEx_DlgCtrlsDlg类名,弹出如图4.24所示的快捷菜单。 图4.24 弹出的快捷菜单
35
4.2.1 控件的创建方法 4) 从快捷菜单中选择Add Member Variable(添加成员变量),在出现的对话框中
定义一个CButton类对象m_btnWnd,通常以“m_”来作为变量的开头,表示“成 员”(member)的意思。如图4.25所示,单击[OK]按钮。 图4.25 添加成员变量
36
4.2.1 控件的创建方法 (5) 在项目工作区窗口的ClassView页面中,双击OnInitDialog函数名,在该函数
中添加下列代码: BOOL CEx_DlgCtrlsDlg::OnInitDialog() { CDialog::OnInitDialog(); … m_btnWnd.Create("你好", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, CRect(20, 20, 120, 60), this, 201); // 创建 CFont *font = this->GetFont(); // 获取对话框的字体 m_btnWnd.SetFont(font); // 设置控件字体 return TRUE; // return TRUE unless you set the focus to a control } 由于OnInitDialog函数在对话框初始化时被调用,因此将对话框中的一些初始化 代码都添加在此函数中。代码中,Create用来创建一个按钮控件,该函数第一个 参数用来指定该按钮的标题,第二个参数用来指定控件的风格,第三个参数用来 指定它在父窗口中的位置和大小,第四个参数用来指定父窗口指针,最后一个参 数是指定该控件的标识值。
37
4.2.1 控件的创建方法 (6) 编译并运行,结果如图4.26所示。 图4.26 控件创建的结果
38
4.2.2 控件的消息及消息映射 当控件的状态发生改变时,控件就会向其父窗口发送消息,这个消息称为“通知
消息”。对于每个消息,系统都会用一个MSG结构来记录,MSG具有下列结构: typedef struct tagMSG { // msg HWND hwnd; // 接收到消息的窗口句柄 UINT message; // 消息 WPARAM wParam; // 消息的附加信息,它的含义取决于message LPARAM lParam; // 消息的附加信息,它的含义取决于message DWORD time; // 消息传送时的时间 POINT pt; // 消息传送时,光标所在的屏幕坐标 } MSG; 对于一般控件来说,其通知消息通常是一条WM_COMMAND消息,这条消息的 wParam参数的低位字中含有控件标识符,wParam参数的高位字则为通知代 码,lParam参数则是指向控件的句柄。 而对于有些控件,其通知消息通常是一条WM_NOTIFY消息,这条消息的 wParam参数是发送通知消息的控件的标识符,而lParam参数则是指向一个结构 指针。
39
4.2.2 控件的消息及消息映射 1. 映射控件消息 在MFC中,映射一个控件消息是非常简便的。例如下面的步骤是用来映射按钮命
令消息。 打开Ex_DlgCtrls应用程序项目。将项目工作区窗口切换到ResourseView页面,双击Dialog资源下的标识IDD_EX_DLGCTRLS_DIALOG,打开该对话框资源模板。 删除“TODO: 在这里设置对话控制。”控件,添加一个按钮控件,保留其默认属 性。如图4.27所示。 图4.27 添加一个按钮
40
4.2.2 控件的消息及消息映射 (4) 按快捷键Ctrl+W,打开MFC ClassWizard对话框,查看“Class name”列表中是否选择了 CEx_DlgCtrlsDlg,在IDs列表中选择IDC_BUTTON1,这是添加按钮后,系统自动为此按 钮设置的默认标识符,然后在Messages框中选择BN_CLICKED消息。 (5) 单击[Add Function]按钮或双击BN_CLICKED消息,出现“Add Member Function”对话 框,在这里可以输入成员函数的名称,系统默认的函数名为OnButton1。如图4.28所示。 图4.28 添加按钮消息映射函数
41
4.2.2 控件的消息及消息映射 (6) 单击[OK]按钮,在MFC ClassWizard的“Member functions”列表中将列出新增 加的成员函数。选择此函数,单击[Edit Code]按钮(或直接在函数名双击鼠标), 开发环境的文档窗口中将自动打开该函数所在的源代码文件,并定位到该函数的 实现代码处。在此成员函数中添加下列代码: void CEx_DlgCtrlsDlg::OnButton1() { MessageBox("你按下了\"Button1\"按钮!"); } (7) 编译并运行,当单击[Button1]按钮时,就会执行OnButton1函数,弹出一个 消息对话框。 这就是按钮BN_CLICKED消息的映射过程,其他控件的消息也可以类似操作。
42
4.2.2 控件的消息及消息映射 2. 映射控件通用消息 上述过程是映射一个控件的某一个消息,事实上也可通过WM_COMMAND消息的映射
来处理一个或多个控件的通用消息,如下面的步骤: 打开MFC ClassWizard对话框,在“Class name”列表中是否选择了CEx_DlgCtrlsDlg, 在IDs列表中选择CEx_DlgCtrlsDlg,在Messages框中找到并双击OnCommand,这样 OnCommand消息函数就添加好了,如图4.29所示。 图4.29 添加OnCommand函数重载
43
4.2.2 控件的消息及消息映射 (2) 在OnCommand函数中添加下列代码:
BOOL CEx_DlgCtrlsDlg::OnCommand(WPARAM wParam, LPARAM lParam) { WORD nCode = HIWORD(wParam); // 控件的通知消息 WORD nID = LOWORD(wParam); // 控件的ID值 if ((nID == 201)&&(nCode == BN_CLICKED)) MessageBox("你按下了\"你好\"按钮!"); if ((nID == IDC_BUTTON1)&&(nCode == BN_CLICKED)) MessageBox("这是在OnCommand处理的结果!"); return CDialog::OnCommand(wParam, lParam); } 注意:第一条if语句中,201是前面用Create创建按钮时指定的标识值。 (3) 编译并运行。当单击如前图4.27所示的[Button1]按钮时,就会弹出一个消息 对话框。
44
4.2.3 控件的数据交换(DDX)和数据校验(DDV)
使用MFC ClassWizard可以很容易地为一个控件定义关联变量并可设置其数据范 围。例如,下面的步骤是为CEx_DlgCtrlsDlg类的按钮控件IDC_BUTTON1添加 并使用其关联变量m_RelBtn。 (1) 打开MFC ClassWizard,并切换到Member Variables页面,如图4.30所示。 图4.30 “Member Variables”页面
45
4.2.3 控件的数据交换(DDX)和数据校验(DDV)
(2) 选定Class name为CEx_DlgCtrlsDlg,然后在Control IDs列表中,选定所要 关联的控件ID标识符IDC_BUTTON1,双击鼠标左键或单击[Add Variable]按 钮,弹出Add Member Variable对话框,在对话框设置变量的名称、类别和数据 类型,如图4.31所示。 图4.31 “Add Member Variable”对话框
46
4.2.3 控件的数据交换(DDX)和数据校验(DDV)
(3) 在Member variable name框中填好与控件相关联的成员变量m_RelBtn,单击 [OK]按钮,又回到MFC ClassWizard对话框的Member Variables页面中,在 Control IDs列表中出现刚才添加的控件关联变量(或直接称之为“控件变量”)。 (4) 单击[确定]按钮后,打开CEx_DlgCtrlsDlg类源文件,可以发现MFC ClassWizard对上述操作作了以下三方面的修改。 ●在Ex_DlgCtrlsDlg.h文件中,添加控件关联变量的声明,代码如下面的加粗部 分: // Dialog Data //{{AFX_DATA(CEx_DlgCtrlsDlg) enum { IDD = IDD_EX_DLGCTRLS_DIALOG }; // 枚举类型 CButton m_RelBtn; CString m_strEdit; //}}AFX_DATA
47
4.2.3 控件的数据交换(DDX)和数据校验(DDV)
●在Ex_DlgCtrlsDlg.cpp文件中的CEx_DlgCtrlsDlg构造函数实现代码处,添加了 控件变量的一些初始代码: CEx_DlgCtrlsDlg::CEx_DlgCtrlsDlg(CWnd* pParent /*=NULL*/) : CDialog(CEx_DlgCtrlsDlg::IDD, pParent) { //{{AFX_DATA_INIT(CEx_DlgCtrlsDlg) m_strEdit = _T(""); //}}AFX_DATA_INIT … }
48
4.2.3 控件的数据交换(DDX)和数据校验(DDV)
●在Ex_DlgCtrlsDlg.cpp文件中的DoDataExchange函数体内,添加了控件的 DDX/DDV代码,它们都是一些以DDV_或DDX_开头的函数调用。 void CEx_DlgCtrlsDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); // 调用此函数作为DDX的开始 //{{AFX_DATA_MAP(CEx_DlgCtrlsDlg) DDX_Control(pDX, IDC_BUTTON1, m_RelBtn); DDX_Text(pDX, IDC_EDIT1, m_strEdit); // 将IDC_EDIT1与m_strEdit进行数据交换 DDV_MaxChars(pDX, m_strEdit, 20); // 校验m_strEdit的最大字符个数不超过20 //}}AFX_DATA_MAP }
49
4.2.3 控件的数据交换(DDX)和数据校验(DDV)
(5) 当为一个控件定义一个关联的数据变量后,就可以使用CWnd::UpdateData函 数实现控件数据的输入和读取。例如,将CEx_DlgCtrlsDlg::OnButton1修改成下 列代码: void CEx_DlgCtrlsDlg::OnButton1() { UpdateData(); // 默认参数值是TRUE m_RelBtn.SetWindowText(m_strEdit); } 代码中,UpdateData函数只有一个为TRUE或FALSE的参数。当调用 UpdateData(FALSE)时,数据由控件相关联的成员变量向控件传输,当调用 UpdateData(TRUE)或不带参数的UpdateData时,数据从控件向相关联的成员变 量复制。
50
4.2.3 控件的数据交换(DDX)和数据校验(DDV)
(6) 运行该程序,当在编辑框中输入“Hello”后,单击[Button1]按钮,OnButton1 函数中的UpdateData将编辑框内容保存到m_strEdit变量中,从而执行下一条语 句后按钮的名称就变成了编辑框控件中的内容“Hello”,其结果如图4.33所示 图4.33 使用控件的数据成员变量
51
4.3 常用控件 根据控件的特性和功能,一般可将其分为三类:Windows公共控件、ActiveX控
件以及MFC新增的一些控件等。表4.5列出了本书所用到的常用控件类。 表4.5 常用控件类
52
4.3.1 静态控件和按钮 1. 静态控件 一个静态控件是用来显示一个字符串、框、矩形、图标、位图或增强的图元文
件。它可以被用来作为标签、框或用来分隔其它的控件。一个静态控件一般不接 收用户输入,也不产生通知消息。 在对话框编辑器的控件工具栏中,属于静态控件的有:静态文本( )、组框( ) 和静态图片( )三种。其中,静态图片控件的一般属性对话框如图4.34所示。表 4.6列出了其一般属性的各个项的含义。 在属性对话框中,用户可以选择图片“类型”、“图像”两个组合框中的有关选项内 容,并可将应用程序资源中的图标、位图等内容显示在该静态图片控件中。另 外,用户还可设置其风格来改变控件的外观以及图像在控件的位置等。
53
表4.6 静态图片控件的General和Style属性
1. 静态控件 图4.34 静态图片控件的General属性对话框 表4.6 静态图片控件的General和Style属性
54
4.3.1 静态控件和按钮 2. 按钮 在Windows中所用的按钮是用来实现一种开与关的输入,常见的按钮有3种类
型:按键按钮、单选按钮、复选框按钮,如图4.37所示。 图4.37 按钮的不同类型
55
4.3.1 静态控件和按钮 2. 按钮 (1) 按键按钮。按键按钮通常可以立即产生某个动作,执行某个命令,因此也常
被称为命令按钮。按键按钮有两种风格:标准按键按钮和默认按键按钮。 (2) 单选按钮。单选按钮的外形是在文本前有一个圆圈,当它被选中时,单选按 钮中就标上一个黑点,它可分为一般和自动两种类型。在自动类型中,用户若选 中同组按钮中的某个单选按钮,则其余的单选按钮的选中状态就会清除,保证了 多个选项始终只有一个被选中。 (3) 复选框。复选框的外形是在文本前有一个空心方框,当它被选中时,复选框 中就加上一个“”标记,通常复选框只有选中和未选中两种状态,若复选框前面有 一个灰色是“ ”,则这样的复选框是三态复选框,如图4.37的Check2,它表示复 选框的选择状态是“不确定”。设定成三态复选框的方法是在复选框属性对话框的 Style页面中选中“(状态)Tri-state”项。
56
4.3.1 静态控件和按钮 3. 按钮的消息 在按钮映射的消息中,常见的只有两个:
BN_CLICKED(单击按钮)和BN_DOUBLE- CLICKED(双击按钮)。 4. 按钮选中操作 最常用的按钮操作是设置或获取一个按钮或多个按钮的选中状态。CButton类的 成员函数SetCheck和GetCheck分别用来设置或获取指定按钮的选中状态,其原 型如下: void SetCheck( int nCheck ); int GetCheck( ) const; 其中,nCheck和GetCheck函数返回的值可以是:0表示不选中,1表示选中,2 表示不确定(仅用于三态按钮)。 而对于同组多个单选按钮的选中状态的设置或获取,需要使用通用窗口类CWnd 的成员函数CheckRadioButton和GetCheckedRadioButton,它们的原型如下: void CheckRadioButton( int nIDFirstButton, int nIDLastButton, int nIDCheckButton ); int GetCheckedRadioButton( int nIDFirstButton, int nIDLastButton ); 其中,nIDFirstButton和nIDLastButton分别指定同组单选按钮的第一个和最后一 个按钮ID值,nIDCheckButton用来指定要设置选中状态的按钮ID值,函数 GetCheckedRadioButton返回被选中的按钮ID值。
57
4.3.1 静态控件和按钮 5. 示例:制作问卷调查 问卷调查是日常生活中经常遇到的调查方式。例如,图4.38就是一个问卷调查对
话框,它针对“上网”话题提出了三个问题,每个问题都有四个选项,除最后一个 问题外,其余都是单项选择。 图4.38 上网问卷调查对话框
58
4.3.1 静态控件和按钮 [例Ex_Research] 制作问卷调查 1)创建并设计对话框
(2) Visual C++会自动打开对话框编辑器并显示对话框资源模板。单击对话框编 辑器工具栏上的切换网格按钮,显示对话框网格,将对话框标题改为“上网问卷 调查”。 (3) 调整对话框的大小,删除对话框中间的“TODO: 在这里设置对话控制。”静态 文本控件,将[确定]和[取消]按钮移至对话框的下方,并向对话框中添加组框 (Group)控件,然后调整其大小和位置。 (4) 右击添加的组框控件,从弹出的快捷菜单中选择“属性”菜单,出现该控件的属 性对话框,在属性对话框窗口中可以看到它的ID为默认的IDC_STATIC。将其 Caption属性内容由“Static”改成“你的年龄”。在组框控件的Styles属性中,“水平 对齐”属性用来指定文本在顶部的左边(Left)、居中(Center)还是右边(Right)。默 认(Default)选项表示左对齐。
59
4.3.1 [例Ex_Research] 1)创建并设计对话框
(5) 在组框内添加4个单选按钮,默认的ID依次为IDC_RADIO1、IDC_RADIO2、 IDC_RADIO3和IDC_RADIO4。在其属性对话框中将ID属性内容分别改成 IDC_AGE_L18、IDC_AGE_18T27、IDC_AGE_28T38和IDC_AGE_M38,然后 将其“标题”Caption属性内容分别改成“< 18”、“ ”、“ ”和“> 38”,最后 调整位置,结果如图4.39所示。 图4.39 添加的组框和单选按钮
60
4.3.1 [例Ex_Research] 1)创建并设计对话框
(6) 接下来添加一个静态文本,标题设为“你使用的接入方式:”,然后在其下再添 加4个单选按钮,标题分别是“FTTL或ADSL”、“单位LAN”、“拨号56K”和“其他”, 并将相应的ID属性依次改成:IDC_CM_FTTL、IDC_CM_LAN、IDC_CM_56K 和IDC_CM_OTHER。用对话框编辑器工具栏的按钮命令调整控件左右之间的间 距,结果如图4.40所示。 图4.40 再添加单选框图
61
4.3.1 [例Ex_Research] 1)创建并设计对话框
(7) 在对话框的下方,再添加一个组框控件,其标题为“你上网主要是”。然后添加四个复选框,其标题分别为“收发邮件”、“浏览资料”、“聊天游戏”和“其他”,ID分别为IDC_DO_POP、IDC_DO_READ、IDC_DO_GAME和IDC_DO_OTHER。结果如图4.41所示。 图4.41 三个问题全部添加后的对话框
62
4.3.1 [例Ex_Research] 1)创建并设计对话框 (8) 单击工具栏上的测试对话框按钮 。对话框测试后,可以发现:顺序添加的
(8) 单击工具栏上的测试对话框按钮 。对话框测试后,可以发现:顺序添加的 这8个单选按钮全部变成一组,也就是说,在这组中只有一个单选按钮被选中, 这不符合我们的本意。解决这个问题的最好的办法是将每一组中的第一个单选按 钮的Group(组)属性选中。 (9) 分别将这二个问题中的第一个单选按钮的Group(组)属性均选中。如图4.42所 示是对第二个问题设置的结果。 图4.42 选中“Group”属性
63
4.3.1 [例Ex_Research] 1)创建并设计对话框 (10) 单击对话框编辑器工具栏上的切换辅助线按钮,然后将对话框中的控件调整
到辅助线以内,并适当对其他控件进行调整。这样,整个问卷调查的对话框就设 计好了,单击工具栏上的测试对话框按钮 进行测试。
64
4.3.1 [例Ex_Research] (2) 完善代码
(1) 将项目工作区切换到ClassView(类视图)页面,展开CEx_ResearchDlg类的所 有成员,双击OnInitDialog函数名就会在文档窗口中自动定位到该函数的实现代 码处,在此函数添加下列初始化代码: BOOL CEx_ResearchDlg::OnInitDialog() { CDialog::OnInitDialog(); … CheckRadioButton(IDC_AGE_L18, IDC_AGE_M38, IDC_AGE_18T27); CheckRadioButton(IDC_CM_FTTL, IDC_CM_OTHER, IDC_CM_FTTL); CButton* pBtn = (CButton*)GetDlgItem(IDC_DO_POP); pBtn->SetCheck(1); // 使“收发邮件”复选框选中 return TRUE; // return TRUE unless you set the focus to a control } 代码中,GetDlgItem是CWnd类的一个成员函数,用来获得对话框中控件(参数是 控件的ID标识符)的窗口指针。
65
4.3.1 [例Ex_Research] (2) 完善代码
(2) 用MFC ClassWizard在CEx_ResearchDlg类中添加IDOK按钮的BN_CLICKED消息映 射,并添加下列代码,使得用按[确定]按钮获取用户所作的选择内容。 void CEx_ResearchDlg::OnOK() { CString str, strCtrl; // 定义两个字符串变量,CString是操作字符串的MFC类 // 获取第一个问题的用户选择 str = "你的年龄:"; UINT nID = GetCheckedRadioButton( IDC_AGE_L18, IDC_AGE_M38); GetDlgItemText(nID, strCtrl); // 获取指定控件的标题文本 str = str + strCtrl; // 获取第二个问题的用户选择 str = str + "\n你使用的接入方式:"; nID = GetCheckedRadioButton( IDC_CM_FTTL, IDC_CM_OTHER); // 获取第三个问题的用户选择 str = str + "\n你上网主要是:\n"; UINT nCheckIDs[4]={IDC_DO_POP, IDC_DO_READ, IDC_DO_GAME, IDC_DO_OTHER}; CButton* pBtn;
66
for (int i=0; i<4; i++)
{ pBtn = (CButton*)GetDlgItem(nCheckIDs[i]); if ( pBtn->GetCheck() ) pBtn->GetWindowText( strCtrl ); str = str + strCtrl; str = str + " "; } MessageBox( str ); CDialog::OnOK(); 代码中,GetDlgItemText是CWnd类成员函数,用来获得对话框(或其他窗口)中的指 定控件的窗口文本。在单选按钮和复选框中,控件的窗口文本就是它们的标题属性 内容。该函数有两个参数,第一个参数用来指定控件的标识,第二个参数是返回的 窗口文本。后面的函数GetWindowText的作用与GetDlgItemText相同,也是获取窗 口的文本内容。不过,GetWindowText使用更加广泛,但要注意这两个函数在使用 上的不同。
67
4.3.1 [例Ex_Research] (2) 完善代码 (3) 编译并运行,出现“上网问卷调查”对话框,当回答问题后,按[确定]按钮,出
现如图4.43所示的消息对话框,显示用户选择的内容。 图4.43 显示用户选择的内容
68
4.3.2 编辑框和旋转按钮控件 1. 编辑框 编辑框是一个让用户从键盘输入和编辑文本的矩形窗口,用户可以通过它,很方
便地输入各种文本、数字或者口令,也可使用它来编辑和修改简单的文本内容。 当编辑框被激活且具有输入焦点时,就会出现一个闪动的插入符(又可称为文本 光标),表明当前插入点的位置。 (1) 编辑框的属性和通知消息。用对话框编辑器可以方便地设置编辑框的属性和 风格,如图4.44所示。表4.7还列出其中各项的含义。 当编辑框的文本修改或者被滚动时,会向其父窗口发送一些消息,如表4.8所示。 图4.44 编辑框的属性对话框
69
表4.7 编辑框的Style属性 表4.8 编辑框的通知消息
70
4.3.2 编辑框和旋转按钮控件 1. 编辑框 (2) 编辑框的基本操作。由于编辑框的形式多样,用途各异,因此下面针对编辑
框的不同用途,分别介绍一些常用操作,以实现一些基本功能。 ① 口令设置。口令设置在编辑框中不同于一般的文本编辑框,用户输入的每个 字符都被一个特殊的字符代替显示,这个特殊的字符称为口令字符。默认的口令 字符是“*”,应用程序可以用成员函数CEdit::SetPasswordChar 来定义自己的口 令字符,其函数原型如下: void SetPasswordChar( TCHAR ch ); 其中,参数ch表示设定的口令字符;当ch = 0时,编辑框内将显示实际字符。 ② 选择文本。当在编辑框中编辑文本时,往往需要选定文本作为整体进行各种 编辑操作。用户可以用鼠标或键盘来选择文本。用鼠标来选择文本的操作方法 是:在要选择的文本的一端按下鼠标左键并拖动鼠标,到另一端释放鼠标键。用 键盘来选择文本的方法是:在按光标方向移动键的同时,按住Shift键。 ③ 设置编辑框的页面边距。设置编辑框的页面边距可以使文本在编辑框显示更 具满意效果,这在多行编辑框中尤为重要,应用程序可通过调用成员函数 CEdit::SetMargins来实现,这个函数的原型如下: void SetMargins( UINT nLeft, UINT nRight ); 其中,参数nLeft和nRight分别用来指定左、右边距的像素大小。
71
4.3.2 编辑框和旋转按钮控件 ④ 剪帖板操作。编辑框通过CEdit类的Copy、Paste和Cut成员函数来实现文本的复制、粘
贴、剪切的操作,并还自动支持键盘快捷操作,其对应的快捷健分别为Ctrl+C、Ctrl+V和 Ctrl+X。若应用程序调用CEdit::Undo函数时,则还可撤消当前的操作,再调用一次该函 数,则恢复刚才的操作。例如下面的代码: if (m_Edit.CanUndo()) m_Edit.Undo(); ⑤ 获取多行编辑框文本。获取多行编辑框控件的文本可以有两种方法: 一种是使用DDX/DDV,当将编辑框控件所关联的变量类型选定为CString(字符串类)后,则 不管多行编辑框的文本有多少都可用此变量来保存,从而能简单地解决多行文本的读取。 但这种方法不能单独获得多行编辑框中的某一行文本。 另一种方法是使用编辑框CEdit类的相关成员函数来获取文本。例如,下面的代码将显示编 辑框中第二行的文本内容: char str[100]; if (m_Edit.GetLineCount()>=2) // 判断多行编辑框的文本是否有两行以上 { int nChars; nChars = m_Edit.LineLength(m_Edit.LineIndex(1));// 获取第二行文本的字符个数 // 0表示第一行,1表示第二行,依次类推。LineIndex用于将文本行转换成 // 能被LineLength识别的索引 m_Edit.GetLine(1,str,nChars); // 获取第二行文本 str[nChars] = '\0'; MessageBox(str); } 代码中,由于调用GetLine获得某行文本内容时,并不能自动在文本后添加文本的结束符 ‘\0’,因此需要首先获得某行文本的字符数,然后设置文本的结束符。
72
4.3.2 编辑框和旋转按钮控件 2. 旋转按钮控件 “旋转按钮控件”(也称为上下控件)是一对箭头按钮,用户点击它们来增加或减小
某个值,比如一个滚动位置或显示在相应控件中的一个数字。如图4.45所示。 图4.45 旋转按钮控件及其伙伴窗口 旋转按钮 伙伴窗口
73
4.3.2 编辑框和旋转按钮控件 2. 旋转按钮控件 (1) 旋转按钮控件常用的风格。旋转按钮控件有许多风格,它们都可以通过旋转
按钮控件属性对话框进行设置,如图4.46所示,其中各项的含义见表4.9。 图4.46 旋转按钮控件属性对话框 表4.9 旋转按钮控件的Style属性
74
4.3.2 编辑框和旋转按钮控件 2. 旋转按钮控件 (2) 旋转按钮控件的基本操作。MFC的CSpinButtonCtrl类提供了旋转按钮控件的 各种操作函数,使用它们可以进行基数、范围、位置设置和获取等基本操作。 成员函数SetBase是用来设置其基数的,这个基数值决定了伙伴窗口显示的数字 是十进制还是十六进制。如果成功则返回先前的基数值,如果给出的是一个无效 的基数则返回一个非零值。函数的原型如下: int SetBase( int nBase ); 其中参数nBase表示控件的新的基数,如10表示十进制,16表示十六进制等。与 此函数相对应的成员函数GetBase是获取旋转按钮控件的基数。 成员函数SetPos和SetRange分别用来设置旋转按钮控件的当前位置和范围,它 们的函数原型如下: int SetPos( int nPos ); void SetRange( int nLower, int nUpper ); 其中,参数nPos表示控件的新位置,它必须在控件的上限和下限指定的范围之 内。nLower 和 nUpper表示控件的上限和下限。任何一个界限值都不能大于 0x7fff 或小于 -0x7fff 。与这两个函数相对应的成员函数GetPos和GetRange分别 用来获取旋转按钮控件的当前位置和范围。
75
4.3.2 编辑框和旋转按钮控件 2. 旋转按钮控件 (3) 旋转按钮控件的通知消息。旋转按钮控件的通知消息只有一个:
UDN_DELTAPOS,它是在当控件的当前数值将要改变时向其父窗口发送的。 3. 示例:用对话框输入学生成绩 在一个简单的学生成绩结构中,常常有学生的姓名、学号以及三门成绩等内容。 为了能够输入这些数据,需要设计一个对话框,如图4.47所示。 图4.47 学生成绩输入对话框
76
4.3.2 编辑框和旋转按钮控件 [例Ex_Input] 用对话框输入学生成绩 1) 创建并设计对话框
(1) 用MFC AppWizard(exe)创建一个默认的单文档应用程序Ex_Input。 (2) 添加一个新的对话框资源,通过其属性对话框,将ID标识符改为IDD_INPUT,标题为 “学生成绩输入”,将对话框字体改为“宋体,9号”。将[OK]和[Cancel]按钮标题改为“确定”和 “取消”。 (3) 显示对话框网格,调整对话框的大小,然后将[确定]和[取消]按钮移至对话框的下方。 (4) 向对话框添加如表4.10所示的控件,调整控件的位置,结果如图4.48所示。 表4.10 学生成绩输入对话框添加的控件 图4.48 设计的学生成绩输入对话框
77
4.3.2 [例Ex_Input] 2) 完善CInputDlg类代码
(1) 在MFC ClassWizard的Member Variables页面中,确定Class name中是否已 选择了CInputDlg,选中所需的控件ID标识符,双击鼠标或单击Add Variables按 钮。依次为表4.11控件增加成员变量。 表4.11 控件变量
78
4.3.2 [例Ex_Input] 2) 完善CInputDlg类代码
(2) 用MFC ClassWizard为CInputDlg添加WM_INITDIALOG消息映射,添加下列 代码: BOOL CInputDlg::OnInitDialog() { CDialog::OnInitDialog(); m_spinScore1.SetRange( 0, 100 ); // 设置旋转按钮控件范围 m_spinScore2.SetRange( 0, 100 ); m_spinScore3.SetRange( 0, 100 ); return TRUE; // return TRUE unless you set the focus to a control }
79
4.3.2 [例Ex_Input] 2) 完善CInputDlg类代码
(3) 用MFC ClassWizard为CInputDlg增加IDC_SPIN_S1控件的UDN_DELTAPOS 消息映射,并添加下列代码: void CInputDlg::OnDeltaposSpinS1(NMHDR* pNMHDR, LRESULT* pResult) { NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR; UpdateData(TRUE); // 将控件的内容保存到变量中 m_fScore1 += (float)pNMUpDown->iDelta * 0.5f; if (m_fScore1<0.0) m_fScore1 = 0.0f; if (m_fScore1>100.0) m_fScore1 = 100.0f; UpdateData(FALSE); // 将变量的内容显示在控件中 *pResult = 0; } 代码中,NM_UPDOWN结构用于反映旋转控件的当前位置(由成员iPos指定)和 增量大小(由成员iDelta指定)。
80
4.3.2 [例Ex_Input] 3) 调用对话框 (1) 打开Ex_Input单文档应用程序的菜单资源,添加顶层菜单项“测试(&T)”,在其下添加一 个菜单项“学生成绩输入(&I)”,ID为ID_TEST_INPUT。 (2) 用MFC ClassWizard为CMainFrame类添加菜单项ID_TEST_INPUT的COMMAND消息 映射,取默认的映射函数名,并添加下列代码: void CMainFrame::OnTestInput() { CInputDlg dlg; if (IDOK == dlg.DoModal()) { // 获取对话框数据 CString str; str.Format("%s, %s, %4.1f, %4.1f, %4.1f", dlg.m_strName, dlg.m_strNO, dlg.m_fScore1, dlg.m_fScore2, dlg.m_fScore3 ); AfxMessageBox(str); } 代码中,if语句是判断用户是否单击对话框的[确定]按钮。Format是CString类的一个经常使 用的成员函数,它通过格式操作使任意类型的数据转换成一个字符串。该函数的第一个参 数是带格式的字符串,其中的“%s”就是一个格式符,每一个格式符依次对应于该函数的后 面参数表中的参数项。
81
4.3.2 [例Ex_Input] 3) 调用对话框 (3) 在文件MainFrm.cpp的前面添加CInputDlg类的头文件包含:
#include "MainFrm.h" #include "InputDlg.h" (4) 编译并运行,在应用程序的菜单上,选择“测试”→“学生成绩输入”菜单项,将 弹出如前图4.47所示的对话框。单击成绩1的旋转按钮控件将以0.5增量来改变它 的伙伴窗口的数值。而成绩2和成绩3的旋转按钮控件由于设置了Set buddy integer属性,因此它按默认增量1自动改变伙伴窗口的数值。
82
4.3.3 列表框 1. 列表框的风格和消息 按性质来分,列表框有单选、多选、扩展多选以及非选四种类型,如图4.50所示。
图4.50 不同类型的列表框
83
1. 列表框的风格和消息 列表框还有一系列其它风格,用来定义列表框的外观及操作方式,这些风格可在
如图4.51所示的列表框属性对话框中设置。表4.12列出Style各项的含义。 图4.51 列表框的属性对话框
84
1. 列表框的风格和消息 表4.12 列表框的Style属性
85
1. 列表框的风格和消息 当列表框中发生了某个动作,如用户双击选择了列表框中某一项时,列表框就会
向其父窗口发送一条通知消息。常用的通知消息如表4.13所示。 表4.13 列表框的通知消息
86
4.3.3 列表框 2. 列表框的基本操作 需要注意的是:列表框的项除了用字符串来标识外,还常常通过索引来确定。索引表明项目在列表框中排列的位置,它是以0为基数的,即列表框中第一项的索引是0,第二项的索引是1,依次类推。 (1) 添加列表项。列表框创建时是一个空的列表,需要用户添加或插入一些列表项。CListBox类成员函数AddString 和InsertString 分别用来添加列表项,其函数原型如下: int AddString( LPCTSTR lpszItem ); int InsertString( int nIndex, LPCTSTR lpszItem ); 其中,列表项的字符串文本由参数lpszItem来指定。虽然两个函数成功调用时都 将返回列表项在列表框的索引,错误时返回LB_ERR,空间不够时,返回 LB_ERRSPACE。但InsertString函数不会对列表项进行排序,不管列表框控件 是否具有sort属性,只是将列表项插在指定索引的列表项之前,若nIndex等于-1, 则列表项添加在列表框末尾。而AddString函数当列表框控件具有sort属性时会自 动将添加的列表项进行排序。函数原型中,LPCTSTR类型用来表示一个常值字符 指针,这里可以将其理解成是一个常值字符串类型。
87
2. 列表框的基本操作 (2) 删除列表项。CListBox类成员函数DeleteString和ResetContent分别用来删除
指定的列表项和清除列表框所有项目。它们的函数原型如下: int DeleteString( UINT nIndex ); // nIndex指定要删除的列表项的索引 void ResetContent( ); (3) 查找列表项。为了保证列表项不会重复地添加在列表框中,有时还需要对列 表项进行查找。CListBox类成员函数FindString 和FindStringExact分别用来在列 表框中查找所匹配的列表项。其中,FindStringExact的查找精度最高。 int FindString( int nStartAfter, LPCTSTR lpszItem ) const; int FindStringExact( int nIndexStart, LPCTSTR lpszFind ) const; 其中,lpszFind和lpszItem指定要查找的列表项文本,nStartAfter和nIndexStart 指定查找的开始位置,若为-1,则从头至尾查找。查到后,这两个函数都将返回 所匹配列表项的索引,否则返回LB_ERR。
88
2. 列表框的基本操作 (4) 列表框的单项选择。当选中列表框中某个列表项,用户可以使用
CListBox::GetCurSel来获取这个结果,与该函数相对应的CListBox::SetCurSel 函数是用来设定某个列表项呈选中状态(高亮显示)。 int GetCurSel( ) const; // 返回当前选择项的索引 int SetCurSel( int nSelect ); 其中,nSelect指定要设置的列表项索引,错误时这两个函数都将返回LB_ERR。 若要获取某个列表项的字符串,可使用下列函数: int GetText( int nIndex, LPTSTR lpszBuffer ) const; void GetText( int nIndex, CString& rString ) const; 其中,nIndex指定列表项索引,lpszBuffer 和rString是用来存放列表项文本。
89
2. 列表框的基本操作 (5) 列表框的多项选择。当在列表框的Style属性对话框中选中多选(Multiple)或扩展多
选(Extended)类型后,就可以在列表框中进行多项选择。要想获得选中的多个选项, 需要用MFC ClassWizard映射列表框控件的LBN_SELCHANGE消息,并添加类似下 面的一些代码: void CListBoxDlg::OnSelchangeList1() { int nCount = m_list.GetSelCount(); // 获取用户选中的项数 if (nCount == LB_ERR) return; int *buffer = new int[nCount]; // 开辟缓冲区 m_list.GetSelItems(nCount,buffer); // 将各个选项的索引号内容存放在缓冲区中 CString allStr = NULL, str; for (int i=0; i<nCount; i++) m_list.GetText(buffer[i], str); // 获得各个索引的项目文本 allStr = allStr + "[" + str + "]"; // 处理项目文本 } delete []buffer; // 释放内存 // MessageBox(allStr); // 处理获得的文本
90
4.3.3 列表框 3. 示例:城市邮政编码 在一组城市邮政编码中,城市名和邮政编码是一一对应的。为了能添加和删除城
市邮政编码列表项,需要设计一个这样的对话框,如图4.52所示。 图4.52 城市邮政编码 实现本例有两个要点:一是在添加时需要通过FindString 或FindStringExact来判断添加的列表项是否重复,然后通过SetItemData将邮政编码(将它视为一个32位整数)与列表项关联起来;二是由于删除操作是针对当前选中的列表项的,如果当前没有选中的列表项则应通过EnableWindow(FLASE)使[删除]按钮灰显,即不能单击它。
91
[例Ex_City] 创建并使用城市邮政编码对话框
添加并设计对话框 用MFC AppWizard(exe)创建一个默认的单文档应用程序Ex_City。 向应用程序中添加一个对话框资源IDD_CITYZIP,标题定为“城市邮政编码”,字 体设为“宋体,9号”,创建此对话框类为CCityDlg。 删除原来的[Cancel]按钮,将[OK]按钮标题改为“退出”。 打开对话框网格,参看图4.52的控件布局,用编辑器为对话框添加如表4.14所示 的一些控件。 表4.14 城市邮政编码对话框添加的控件
92
[例Ex_City] 2) 完善CCityDlg类代码
(1)打开ClassWizard的Member Variables页面,看看Class name是否是 CCityDlg,然后选中所需的控件ID标识符,双击鼠标或单击Add Variables按钮, 依次为下列控件增加成员变量。如表4.15所示。 表4.15 控件变量 (2)将项目工作区切换到ClassView页面,右击CCityDlg类名,从弹出的快捷菜单中选择“Add Member Function”,弹出如图4.53所示的对话框,在Function Type(函数类型)框中输入BOOL,在Function Declaration(函数声明)框中输入IsValidate,单击[OK]按钮。 图4.53 添加成员函数
93
[例Ex_City] (3) 在CCityDlg::IsValidate函数输入下列代码:
BOOL CCityDlg::IsValidate() { UpdateData(); m_strCity.TrimLeft(); if (m_strCity.IsEmpty()) { MessageBox("城市名输入无效!"); return FALSE; } return TRUE; } IsValidate函数的功能是判断城市名编辑框中的内容是否是有效的字符串。代码中, TrimLeft是CString类的一个成员函数,用来去除字符串左边的空格。 (4) 用MFC ClassWizard为对话框添加WM_INITDIALOG消息映射,并添加下列代码: BOOL CCityDlg::OnInitDialog() CDialog::OnInitDialog(); m_dwZipCode = ; // 设置初始的邮政编码 UpdateData( FALSE ); // 将邮政编码显示在控件中 GetDlgItem(IDC_BUTTON_DEL)->EnableWindow( FALSE );// 使[删除]按钮灰显 return TRUE; // return TRUE unless you set the focus to a control
94
[例Ex_City] (5) 打开MFC ClassWizard,切换到Messsage Maps页面,为按钮
IDC_BUTTON_ADD添加BN_CLICKED的消息映射,并增加下列代码: void CCityDlg::OnButtonAdd() { if (!IsValidate()) return; int nIndex = m_ListBox.FindStringExact( -1, m_strCity ); if (nIndex != LB_ERR ) { MessageBox("该城市已添加!"); return; } nIndex = m_ListBox.AddString( m_strCity ); m_ListBox.SetItemData( nIndex, m_dwZipCode ); } (6) 用MFC ClassWizard为按钮IDC_BUTTON_DEL添加BN_CLICKED的消息映射,并增 加下列代码: void CCityDlg::OnButtonDel() int nIndex = m_ListBox.GetCurSel(); if (nIndex != LB_ERR ) m_ListBox.DeleteString( nIndex ); else GetDlgItem(IDC_BUTTON_DEL)->EnableWindow( FALSE );
95
[例Ex_City] (7) 用MFC ClassWizard为列表框IDC_LIST1添加LBN_SELCHANGE(当前选择
项发生改变)的消息映射,并增加下列代码。这样,当单击列表框的城市名时, 将会在编辑框中显示出城市名和邮政编码。 void CCityDlg::OnSelchangeList1() { int nIndex = m_ListBox.GetCurSel(); if (nIndex != LB_ERR ) m_ListBox.GetText( nIndex, m_strCity ); m_dwZipCode = m_ListBox.GetItemData( nIndex ); UpdateData( FALSE ); // 使用当前列表项所关联的内容显示在控件上 GetDlgItem(IDC_BUTTON_DEL)->EnableWindow( TRUE ); }
96
[例Ex_City] 3.调用对话框 (1) 打开Ex_City单文档应用程序的菜单资源,添加顶层菜单项“测试(&T)”,在其
下添加一个菜单项“城市邮政编码(&C)”,ID为ID_TEST_CITY。 (2) 用MFC ClassWizard为CMainFrame类添加菜单项ID_TEST_CITY的COMMAND消息映射,取默认的映射函数名,并添加下列代码: void CMainFrame::OnTestCity() { CCityDlg dlg; dlg.DoModal(); } (3) 在文件MainFrm.cpp的前面添加CCityDlg类的头文件包含: #include "MainFrm.h" #include "CityDlg.h" (4) 编译运行后,在应用程序的菜单上,选择“测试”→“城市邮政编码”菜单项,将 弹出如前图4.52所示的对话框。
97
4.3.4 组合框 作为用户输入的接口,前面的列表框和编辑框各有其优点。例如,列表框中可列
出用户所需的各种可能的选项,这样一来,用户不需要记住这些项,只需进行选 择操作即可,但用户却不能输入列表框中列表项之外的内容。虽然编辑框能够允 许用户输入内容,但却没有列表框的选择操作。于是很自然地产生这样的想法: 把常用的项列在列表框中以供选择,而同时提供编辑框,允许用户输入列表框中 所没有的新项。组合框正是这样的一种控件,它结合列表框和编辑框的特点,取 二者之长,从而完成较为复杂的输入功能。
98
4.3.4 组合框 1. 组合框的风格类型和消息 按照组合框的主要风格特征,可把组合框分为3类:简单组合框、下拉式组合 框、下拉式列表框。
简单组合框和下拉式组合框都包含有列表框和编辑框,但是简单组合框中的列表 框不需要下拉,是直接显示出来的,而当用户单击下拉式组合框中的下拉按钮 时,下拉的列表框才被显示出来。下拉式列表框虽然具有下拉式的列表,却没有 文字编辑功能。如图4.54所示。 图4.54 组合框的类型
99
4.3.4 组合框 组合框还有其他一些风格,这些风格可在如图4.55所示的组合框的属性对话框中 设置。其各项含义见表4.16。
图4.55 组合框的属性对话框 表4.16 组合框的Style属性
100
4.3.4 组合框 在组合框的通知消息中,有的是列表框发出的,有的是编辑框发出的,如表4.17 所示。 表4.17 组合框的通知消息
101
4.3.4 组合框 2. 组合框常见操作 组合框的操作大致分为两类,一类是对组合框中的列表框进行操作,另一类是对
组合框中的编辑框进行操作。这些操作都可以调用CComboBox成员函数来实 现,见表4.18。
102
表4.18 CComboBox类常用成员函数
103
4.3.4 组合框 3. 示例:城市邮政编码和区号 前面的示例中,只是简单的涉及到城市名和邮政编码的对应关系。实际上,城市
名还和区号一一对应,为此本例需要设计这样的对话框,如图4.56所示。 单击[添加]按钮将城市名、邮政编码和区号添加到组合框中,在添加前同样需要 进行重复性的判断。选择组合框中的城市名,将在编辑框中显示出邮政编码和区 号,单击[修改]按钮,将以城市名作为组合框的查找关键字,找到后修改其邮政 编码和区号内容。 图4.56 城市邮政编码和区号
104
[例Ex_CityCode] 创建并使用城市邮政编码和区号对话框
1. 添加并设计对话框 (1) 用MFC AppWizard(exe)创建一个默认的单文档应用程序Ex_CityCode。 (2) 向应用程序中添加一个对话框资源IDD_CITYZONE,标题定为“城市邮政编码 和区号”,字体设为“宋体,9号”,创建此对话框类为CCityZoneDlg。 (3) 删除原来的[Cancel]按钮,将[OK]按钮标题改为“退出”。 (4) 打开对话框网格,参看图4.56的控件布局,为对话框添加如表4.19所示的一 些控件。 表4.19 城市邮政编码和区号对话框添加的控件
105
[例Ex_CityCode] 2. 完善CCityZoneDlg类代码
(1) 打开MFC ClassWizard的Member Variables页面,看看Class name是否是 CCityZoneDlg,然后选中所需的控件ID标识符,双击鼠标或单击Add Variables 按钮。依次为下列控件增加成员变量。如表4.20所示。 (2) 将项目工作区切换到ClassView页面,右击CCityZoneDlg类名,从弹出的快 捷菜单中选择“Add Member Function”,弹出Add Member Function对话框,在 Function Type(函数类型)框中输入BOOL,在Function Declaration(函数声明)框 中输入IsValidate,单击[OK]按钮。 表4.20 控件变量
106
[例Ex_CityCode] 2. 完善CCityZoneDlg类代码
(3) 在CCityZoneDlg::IsValidate函数输入下列代码: BOOL CCityZoneDlg::IsValidate() { UpdateData(); m_strCity.TrimLeft(); if (m_strCity.IsEmpty()) { MessageBox("城市名输入无效!"); return FALSE; } m_strZip.TrimLeft(); if (m_strZip.IsEmpty()) { MessageBox("邮政编码输入无效!"); return FALSE; } m_strZone.TrimLeft(); if (m_strZone.IsEmpty()) { MessageBox("区号输入无效!"); return FALSE; } return TRUE; }
107
[例Ex_CityCode] 2. 完善CCityZoneDlg类代码
(4) 打开MFC ClassWizard,切换到Messsage Maps页面,为按钮 IDC_BUTTON_ADD添加BN_CLICKED的消息映射,并增加下列代码: void CCityZoneDlg::OnButtonAdd() { if (!IsValidate()) return; int nIndex = m_ComboBox.FindStringExact( -1, m_strCity ); if (nIndex != CB_ERR ) { MessageBox("该城市已添加!"); return; } CString strData; strData.Format(“%s,%s”, m_strZip, m_strZone); // 将邮政编码和区号合并为 一个字符串 m_ComboBox.SetItemDataPtr( nIndex, new CString(strData) ); }
108
[例Ex_CityCode] 2. 完善CCityZoneDlg类代码
(5) 用MFC ClassWizard为按钮IDC_BUTTON_CHANGE添加BN_CLICKED的消 息映射,并增加下列代码: void CCityZoneDlg::OnButtonChange() { if (!IsValidate()) return; int nIndex = m_ComboBox.FindStringExact( -1, m_strCity ); if (nIndex != CB_ERR ) delete (CString*)m_ComboBox.GetItemDataPtr( nIndex ); CString strData; strData.Format("%s,%s", m_strZip, m_strZone); m_ComboBox.SetItemDataPtr( nIndex, new CString(strData) ); }
109
[例Ex_CityCode] 2. 完善CCityZoneDlg类代码
(7) 用MFC ClassWizard为组合框IDC_COMBO1添加CBN_SELCHANGE(当前 选择项发生改变)的消息映射,并增加下列代码: void CCityZoneDlg::OnSelchangeCombo1() { int nIndex = m_ComboBox.GetCurSel(); if (nIndex != CB_ERR ) m_ComboBox.GetLBText( nIndex, m_strCity ); CString strData = *(CString*)m_ComboBox.GetItemDataPtr( nIndex ); // 分解字符串 int n = strData.Find(','); m_strZip = strData.Left( n ); // 前面的n个字符 m_strZone = strData.Mid( n+1 ); // 从中间第n+1字符到未尾的字符串 UpdateData( FALSE ); }
110
[例Ex_CityCode] 2. 完善CCityZoneDlg类代码
(7) 用MFC ClassWizard为对话框添加WM_DESTROY的消息映射,并增加下列 代码: void CCityZoneDlg::OnDestroy() // 此消息是当对话框关闭时发送的 { for (int nIndex = m_ComboBox.GetCount()-1; nIndex>=0; nIndex--) // 删除所有与列表项相关联的CString数据,并释放内存 delete (CString *)m_ComboBox.GetItemDataPtr(nIndex); } CDialog::OnDestroy();
111
[例Ex_CityCode] 3. 调用对话框 (1) 打开Ex_CityCode单文档应用程序的菜单资源,添加顶层菜单项“测试(&T)”,
在其下添加一个菜单项“城市邮政编码和区号(&Z)”,ID为ID_TEST_CITYZONE。 (2) 用MFC ClassWizard为CMainFrame类添加菜单项ID_TEST_CITYZONE的 COMMAND消息映射,取默认的映射函数名,并添加下列代码: void CMainFrame::OnTestCityzone() { CCityZoneDlg dlg; dlg.DoModal(); } (3) 在文件MainFrm.cpp的前面添加CCityZoneDlg类的头文件包含: #include "MainFrm.h" #include "CityZoneDlg.h" (4) 编译运行并测试。
112
4.3.5 进展条、滚动条和滑动条 1. 进展条 进展条是一个如图4.58所示的控件。除了能表示一个过程进展情况外,使用进展
条还可表明温度、水平面或类似的测量值。 (1) 进展条的风格。打开进展条的属性对话框,如图4.59所示,可以看到它的风 格属性并不是很多。其中,边框(Border)用来指定进展条是否有边框,垂直 (Vertical)用来指定进展是水平还是垂直的,若选中,则为垂直的。平滑(Smooth) 表示平滑地填充进展条,若不选中则表示将用块来填充,就像图4.58那样。 图4.58 进展条 图4.59 进展条Style属性对话框
113
4.3.5 进展条、滚动条和滑动条 1. 进展条 (2) 进展条的基本操作。进展条的基本操作有:设置其范围、当前位置、设置增量等。这些
操作都是通过CProgressCtrl类的相关成员函数来实现的。 int SetPos( int nPos ); int GetPos(); 这两个函数分别用来设置和获取进展条的当前位置。需要说明的是,这个当前位置是指在 SetRange中的上限和下限范围之间的位置。 void SetRange( short nLower, short nUpper ); void SetRange32(int nLower, int nUpper ); void GetRange( int & nLower, int& nUpper ); 它们分别用来设置和获取进展条范围的上限和下限值。一旦设置后,还会重画此进展条来 反映新的范围。成员函数SetRange32为进展条设置32位的范围。参数nLower和nUpper 分 别表示范围的下限(默认值为0)和上限(默认值为100)。 int SetStep( int nStep ); 该函数用来设置进展条的步长并返回原来的步长,默认步长为10。 int StepIt(); 该函数将当前位置向前移动一个步长并重画进展条以反映新的位置。函数返回进展条上一 次的位置。
114
4.3.5 进展条、滚动条和滑动条 2. 滚动条 滚动条是一个独立的窗口,虽然它具有直接的输入焦点,但却不能自动地滚动窗
口内容,因此,它的使用受到一定的限制。 根据滚动条的走向,可分为垂直滚动条和水平滚动条两种类型。这两种类型滚动 条的组成部分都是一样的,两端都有两个箭头按钮,中间有一个可沿滚动条方向 移动的滚动块。如图4.60所示。 图4.60 滚动条外观 滚动箭头按钮 滚动条 滚动块
115
4.3.5 进展条、滚动条和滑动条 2. 滚动条 (1) 滚动条的基本操作。滚动条的基本操作一般包括设置和获取滚动条的范围及滚动块的相
应位置。 由于滚动条控件的默认滚动范围是0到0,因此在使用滚动条之前必须设定其滚动范围。在 MFC的CScrollBar类中,函数SetScrollRange是用来设置滚动条的滚动范围,其原型为: SetScrollRange( int nMinPos, int nMaxPos, BOOL bRedraw = TRUE ); 其中,nMinPos和nMaxPos表示滚动位置的最小值和最大值。bRedraw为重画标志,当为 TRUE时,滚动条被重画。 在CScrollBar类中,设置滚动块位置操作是由SetScrollPos函数来完成的,其原型如下: int SetScrollPos( int nPos, BOOL bRedraw = TRUE ); 其中,nPos表示滚动块的新位置,它必须是在滚动范围之内。 与SetScrollRange 和SetScrollPos相对应的两个函数是分别用来获取滚动条的当前范围以 及当前滚动位置: void GetScrollRange( LPINT lpMinPos, LPINT lpMaxPos ) ; int GetScrollPos(); 其中,LPINT是整型指针类型,lpMinPos和lpMaxPos分别用来返回滚动块最小和最大滚动 位置。
116
4.3.5 进展条、滚动条和滑动条 2. 滚动条 (2) WM_HSCROLL或WM_VSCROLL消息。当用户对滚动条进行操作时,滚动
动条和垂直滚动条)。这些消息是通过MFC ClassWizard在其对话框(滚动条的父 窗口)中进行映射的,并产生相应的消息映射函数OnHScroll和OnVScroll,这两 个函数具有下列原型: afx_msg void OnHScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar ); afx_msg void OnVScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar ); 其中,nPos表示滚动块的当前位置,pScrollBar表示由滚动条控件的指针, nSBCode表示滚动条的通知消息。图4.61表示当鼠标单击滚动条的不同部位 时,所产生的不同通知消息。
117
2. 滚动条 图4.61 滚动条通知代码与位置的关系 SB_LINEUP SB_PAGEUP SB_THUMBTRACK和
SB_LINELEFT SB_LINERIGHT SB_PAGELEFT SB_PAGERIGHT 图4.61 滚动条通知代码与位置的关系 SB_LINEUP SB_PAGEUP SB_THUMBTRACK和 SB_THUMBPOSITION SB_PAGEDOWN SB_LINEDOWN
118
2. 滚动条 表4.21列出了各通知消息的含义。 表4.21 滚动条的通知消息
119
4.3.5 进展条、滚动条和滑动条 3. 滑动条 滑动条控件是由滑动块和可选的刻度线组成的。当用户用鼠标或方向键移动滑动
块时,该控件发送通知消息来表明这些改变。 滑动条是按照应用程序中指定的增量来移动。例如,如果用户指定此滑动条的范 围为5,则滑动块只能有6个位置:在滑动条控件最左边的一个位置和另外5个在 此范围内每隔一个增量的位置。通常,这些位置都是由相应的刻度线来标识。如 图4.62所示。 图4.62 带刻度线的滑动条 滑动块 刻度线
120
4.3.5 进展条、滚动条和滑动条 3. 滑动条 (1) 滑动条的风格和消息。滑动条控件有许多风格,它们都可以通过滑动条控件
的属性对话框进行设置,如图4.63所示。表4.22列出该属性对话框的各项含义。 图4.63 滑动条属性对话框 表4.22 滑动条控件的Style属性
121
3. 滑动条 (2) 滑动条的基本操作。MFC的CSliderCtrl 类提供了滑动条控件的各种操作函
数,这其中包括范围、位置设置和获取等。 成员函数SetPos和SetRange分别用来设置滑动条的位置和范围,其原型如下: void SetPos( int nPos ); void SetRange( int nMin, int nMax, BOOL bRedraw = FALSE ); 其中,参数nPos表示新的滑动条位置。bMin和nMax表示滑动条的最小和最大位 置,bRedraw表示重画标志,为TRUE时,滑动条被重画。与这两个函数相对应 的成员函数GetPos和GetRange是分别用来获取滑动条的位置和范围的。
122
3. 滑动条 成员函数SetTic用来设置滑动条控件中的一个刻度线的位置。函数成功调用后返 回非零值;否则返回0。函数原型如下:
BOOL SetTic( int nTic ); 其中,参数nTic表示刻度线的位置。 成员函数SetTicFreq用来设置显示在滑动条中的刻度线的疏密程度。其函数原型 如下: void SetTicFreq( int nFreq ); 其中,参数nFreq表示刻度线的疏密程度。例如,如果参数被设置为2,则在滑动 条的范围中每两个增量显示一个刻度线。要使这个函数有效,必须在属性对话框 中选中Auto ticks项。 成员函数ClearTics用来从滑动条控件中删除当前的刻度线。其函数原型如下: void ClearTics( BOOL bRedraw = FALSE ); 其中,参数bRedraw表示重画标志。若该参数为TRUE,则在选择被清除后重画 滑动条。 成员函数SetSelection用来设置一个滑动条控件中当前选择的开始和结束位置。 其函数原型如下: void SetSelection( int nMin, int nMax ); 其中,参数nMin、nMax表示滑动条的开始和结束位置。
123
4.3.5 进展条、滚动条和滑动条 4. 示例:调整对话框背景颜色 设置对话框背景颜色有许多方法,这里采用最简单的也是最直接的方法,即通过
映射WM_CTLCOLOR(当子窗口将要绘制时发送的消息,以便能使用指定的颜色 绘制控件)来达到改变背景颜色的目的。本例通过滚动条和两个滑动条来调整 Visual C++所使用的RGB颜色的三个分量:R(红色)、G(绿色)和B(蓝色),如图 4.64所示。 图4.64 调整对话框背景颜色
124
4. 示例:调整对话框背景颜色 [例Ex_Color] 调整对话框背景颜色 1) 添加并设计对话框
(1) 用MFC AppWizard(exe)创建一个默认的单文档应用程序Ex_Color。 (2) 向应用程序中添加一个对话框资源IDD_COLOR,标题定为“调整对话框背景 颜色”,字体设为“宋体,9号”,创建此对话框类为CBkColorDlg。 (3) 删除原来的[Cancel]按钮,将[OK]按钮的标题改为“退出”。 (4) 打开对话框网格,参看图4.64的控件布局,为对话框添加如表4.23所示的一 些控件。 表4.23 对话框添加的控件
125
例Ex_Color] 2) 完善CBkColorDlg类代码
(1) 打开ClassWizard的Member Variables页面,看看Class name是否是CBkColorDlg,选中所需的控件ID标识符,双击鼠标。依次为下列控件增加成员变量。如表4.24所示。 表4.24 控件变量
126
例Ex_Color] 2) 完善CBkColorDlg类代码
(2) 为CBkColorDlg类添加两个成员变量,一个是int型m_nRedValue,用来设置 颜色RGB中的红色分量,另一个是画刷CBrush类对象m_Brush,用来设置对话 框背景所需要的画刷。 (3) 用MFC ClassWizard为CBkColorDlg类添加WM_INITDIALOG消息映射,并 添加下列初始化代码: BOOL CBkColorDlg::OnInitDialog() { CDialog::OnInitDialog(); m_scrollRed.SetScrollRange(0, 255); m_sliderBlue.SetRange(0, 255); m_sliderGreen.SetRange(0, 255); m_nBlue = m_nGreen = m_nRedValue = 192; UpdateData( FALSE ); m_scrollRed.SetScrollPos(m_nRedValue); return TRUE; // return TRUE unless you set the focus to a control }
127
例Ex_Color] 2) 完善CBkColorDlg类代码
(4) 用MFC ClassWizard为CBkColorDlg类添加WM_HSCROLL消息映射,并添加下列代码: void CBkColorDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { int nID = pScrollBar->GetDlgCtrlID(); // 获取对话框中控件ID值 if (nID == IDC_SCROLLBAR_RED) { //滚动条产生的水平滚动消息 switch(nSBCode){ case SB_LINELEFT: m_nRedValue--; // 单击滚动条左边箭头 break; case SB_LINERIGHT: m_nRedValue++; // 单击滚动条右边箭头 case SB_PAGELEFT: m_nRedValue -= 10; break; case SB_PAGERIGHT: m_nRedValue += 10; break; case SB_THUMBTRACK: m_nRedValue = nPos; break; } if (m_nRedValue<0) m_nRedValue = 0; if (m_nRedValue>255) m_nRedValue = 255; m_scrollRed.SetScrollPos(m_nRedValue); Invalidate(); // 使对话框无效,强迫系统重绘对话框 CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
128
例Ex_Color] 2) 完善CBkColorDlg类代码
(5) 用MFC ClassWizard为CBkColorDlg类添加WM_CTLCOLOR消息映射,并添 加下列代码: HBRUSH CBkColorDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { UpdateData(TRUE); COLORREF color = RGB(m_nRedValue, m_nGreen, m_nBlue); m_Brush.Detach(); // 使画刷和对象分离 m_Brush.CreateSolidBrush(color); // 创建颜色画刷 pDC->SetBkColor( color ); // 设置背景颜色 return (HBRUSH)m_Brush; // 返回画刷句柄,以便系统使此画刷绘制对话框 } 代码中,COLORREF是用来表示RGB颜色的一个32位的数据类型,它是Visual C++中一种专门用来定义颜色的数据类型。(画刷的详细用法以后还会讨论)
129
例Ex_Color] 3. 调用对话框 (1) 打开Ex_Color单文档应用程序的菜单资源,添加顶层菜单项“测试(&T)”,在
其下添加一个菜单项“调整对话框背景颜色(&O)”,ID为ID_TEST_COLOR。 (2) 用MFC ClassWizard为CMainFrame类添加菜单项ID_TEST_COLOR的 COMMAND消息映射,取默认的映射函数名,并添加下列代码: void CMainFrame::OnTestColor() { CBkColorDlg dlg; dlg.DoModal(); } (3)在文件MainFrm.cpp的前面添加CBkColorDlg类的头文件包含: #include "MainFrm.h" #include "BkColorDlg.h" (4) 编译运行并测试。
130
4.4 通用对话框和消息对话框 4.4.1 通用对话框 Windows提供了一组标准用户界面对话框,它们都有相应的MFC库中的类来支
用程序早已使用过它们,其中包括Visual C++。所有这些通用对话框类都是从一 个公共的基类CCommonDialog派生而来。表4.25列出了这些通用对话框。 表4.25 MFC的通用对话框
131
4.4.1 通用对话框 通用文件对话框类CFileDialog的构造函数的原型如下:
CFileDialog( BOOL bOpenFileDialog, LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR lpszFilter = NULL, CWnd* pParentWnd = NULL ); 参数中,当bOpenFileDialog为TRUE时表示文件打开对话框,为FALSE时表 示文件保存对话框。lpszDefExt用来指定文件扩展名。若用户在文件名编辑框中 没有键入扩展名,则系统在文件名后自动添加lpszDefExt指定的扩展名。 lpszFileName用来在文件名编辑框中指定开始出现的文件名,若为NULL时,则 不出现。dwFlags用来指定对话框的界面标志,当为OFN_HIDEREADONLY时 表示隐藏对话框中的“只读”复选框,当为OFN_OVER- WRITEPROMPT时表示 文件保存时,若有指定的文件有重名,则出现提示对话框。pParentWnd用来指 定对话框的父窗口指针。lpszFilter参数用来确定出现在文件列表框中的文件类 型。它由一对或多对字符串组成,每对字符串中第一个字符串表示过滤器名称, 第二个字符串表示文件扩展名,若指定多个扩展名则用“;”分隔,字符串最后用 两个“|”结尾。注意:字符串应好写在一行,若一行写不下则用“\”连接。
132
4.4.2 消息对话框 消息对话框是最简单的一类对话框,它只是用来显示信息的。在Visual C++ 6.0
的MFC类库中就提供相应的函数实现这样的功能,使用时,直接在程序中调用它 们即可。它们的函数原型如下: int AfxMessageBox( LPCTSTR lpszText, UINT nType = MB_OK, UINT nIDHelp = 0 ); int MessageBox( LPCTSTR lpszText, LPCTSTR lpszCaption = NULL, UINT nType = MB_OK ); 这两个函数都是用来创建和显示消息对话框的,它们和前面示例Ex_HelloMsg使 用到的Win32 API函数MessageBox是不同的,前者是MFC类库中的函数。 AfxMessageBox是全程函数,可以用在任何地方。而MessageBox只能控件、对 话框、窗口等一些窗口类中使用。
133
4.4.2 消息对话框 表4.26 消息对话框常用图标类型 表4.27 消息对话框常用按钮类型
134
4.4.2 消息对话框 在使用消息对话框时,图标类型和按钮类型的标识可使用“|”来组合,例如下面的 代码产生如图4.66所示的结果。
int nChoice = MessageBox("你喜欢Visual C++吗?","提问", MB_OKCANCEL|MB_ICONQUESTION); if (nChoice == IDYES) { //... } 图4.66 消息对话框
Similar presentations