VC++6 第六章创建和使用对话框文档格式.docx
《VC++6 第六章创建和使用对话框文档格式.docx》由会员分享,可在线阅读,更多相关《VC++6 第六章创建和使用对话框文档格式.docx(45页珍藏版)》请在冰豆网上搜索。
图6-1 对话框基本原理
6.1.2对话框的类型
对话框分为模式对话框和无模式对话框两种。
当一个模式对话框打开了,在其关闭之前,用户不能转向其它用户界面对象,只能与该对话框进行交互。
我们平时接触到的对话框,大多数都是模式对话框,例如,一个执行菜单命令File->
Save后,Save对话框被打开后,用户不能再做其它工作,只能保存完文件或取消保存文件,关闭对话框窗口后,才能做其它工作。
无模式对话框恰恰相反,当用户打开一个无模式对话框,对话框停留在屏幕上,仍然允许用户与其它用户界面对象进行交互。
无模式对话框最典型的例子是在Word中使用的查找与替换对话框,打开该对话框后,可以交替地进行文档编辑,和查找替换操作。
从第一节的介绍可以看到对话框的设计任务主要包括对话框资源模板的设计,对话框类的设计和对话框的运行,绝大多数对话框的创建任务,模式对话框和无模式对话框都是相同的,只有在对话框与应用程序代码的交互中,也就是对话框的运行中,两者有明显的区别。
6.2设计对话框资源
6.2.1创建对话框
使用AppWizard生成的单文档或多文档应用程序,只有一个默认的About对话框,用于显示应用程序版本信息。
需要使用对话框模板创建自己的对话框资源。
DevelopStudio提供的对话框模板创建了一个基本界面,包括一个OK(确定)按钮和一个Cancel(取消)按钮等。
你可以移动、修改、删除这些控件,或者是增加新的控件到对话框模板,构成应用程序所需的对话框资源。
创建一个对话框资源到工程的步骤:
(1)使用AppWizard生成一个单文档的MFC应用程序Exam6_1。
(2)选择Insert->
Resource菜单命令。
(3)在弹出的InsertResource对话框左边的列表中选择Dialog,单击New按钮。
(4)在项目工作区中选择ResourceView面板,展开Dialog文件夹,可以看到增加了一个对话框资源IDD_DIALOG1,如图6-2所示,双击IDD_DIALOG1,在编辑区出现一个对话框模板。
对话框模板
对话框资源ID
控件工具栏
图6-2Exam6_1对话框设计_新建对话框资源
6.2.2增加控件
一个控件是能够放置在一个对话框中,提供应用程序与用户交互的某种功能。
例如,EditBox提供用户文本输入的场所,一组RadioButton提供用户对某一主题的单项选择。
MFC将控件设计为对话框窗口的子窗口,控件通过事件通知消息与父窗口联系。
在一个对话框资源中增加控件的操作十分方便,只需从图6-2所示的控件工具栏中选中要增加的控件,再将此控件拖拉至对话框模板中的确定位置上,松开鼠标按键即生成一个控件。
调整控件的位置和大小的操作与Word中对文本框的操作完全一样。
在默认情况下,控件工具栏总是打开的,如果没有打开,可以在DevelopStudio工具栏后的空白处,单击鼠标右键,在弹出的快捷菜单中选择Controls,便可打开控件工具栏。
图6-3中列出了VC++6.0中支持的标准控件名称,我们可以很方便地从控件工具栏中生成新的控件,但每一种控件都具有不同的特性,需要学习和掌握。
图6-3标准控件
下面我们试着设计一个可以输入5门功课成绩的输入窗口,在上一节生成的对话框资源IDD_DIALOG1中做以下操作,得到如图6-4所示的对话框:
(1)调整对话框模板窗口大小,将OK和Cancel按钮移到窗口的底部。
(2)控件工具栏中选中StaticText(静态文本)控件,拖到对话框模板中。
(3)通过复制和粘贴操作,生成其它四个StaticText控件。
(4)控件工具栏中选中EditBox控件(编辑框),拖到对话框模板中。
(5)通过复制和粘贴操作,生成其它四个EditBox控件
图6-4 EX6对话框设计_增加控件
6.2.3设置控件属性
一个控件相关的属性设置决定了一个控件可操作行为和显示。
例如,控件的ID是控件的一个重要属性,MFC内部是以控件ID来标识一个控件,当消息产生后,是哪一个控件需要进行处理,MFC内部使用的是控件ID。
属性的设置是在与每个控件相对应的属性对话框中进行的,单击鼠标右键,在弹出的快捷菜单中选择Properties,打开属性对话框。
每一种控件的属性对话框都有所不同,与其特性相关,在下一章我们将详细介绍一些常用控件的属性含义。
对上一节的对话框IDD_DIALOG1中的控件作属性设置:
(1)鼠标选中第一个StaticText对象,单击鼠标右键,在弹出的快捷菜单中选择Properties,弹出属性对话框,如图6-5所示。
图6-5 属性对话框设置
(2)修改Caption右边的文本框,输入“高等数学”,单击关闭按钮,关闭属性对话框。
(3)重复步骤
(1)
(2),将其它四个Static控件的Caption改为“大学物理”,“大学英语”,“哲学”和“计算机基础”。
(4)同样的操作打开5个EditBox控件的属性对话框,修改ID为IDC_SCORE1、IDC_SCORE2、IDC_SCORE3、IDC_SCORE4、IDC_SCORE5。
(5)打开按钮OK的属性对话框,修改Caption为“确定”。
(6)打开按钮Cancel的属性对话框,修改Caption为“取消”。
操作完毕,对话框如图6-6所示。
图6-6 EX6对话框设计_设置属性
同样,对话框的属性设计也是在对话框的属性对话框中设置,在对话框任意空白处单击鼠标右键,在弹出的快捷菜单中选择Properties,如图6-7所示。
在Caption中填写“成绩录入”,将成为对话框的标题,单击Font会弹出字体对话框,能设置对话框中显示的字体格式。
其它的几个标签页还提供了选项,可以修改对话框窗口的显示样式,可以自己试一试。
图6-7 对话框属性设置
6.2.4组织和安排控件
当选择了一个对话框资源进入对话框编辑器时,DevelopStudio的菜单栏上会增加一个菜单Layout,如图6-8所示。
Layout菜单提供了在对话框模板中合理布置控件的功能菜单项。
Align提供了控件的六种对齐方式:
左对齐、右对齐、上对齐、下对齐、水平居中、垂直居中。
SpaceEvenly提供了两种等间距方式:
垂直方向等间距、水平方向等间距。
MakeSameSize提供了三种等尺寸方式:
宽相等、高相等、两者都相等。
ArrangeButton提供了两种组织按键的方式:
底部排列、右边排列。
CenterinDialog提供了两种居中方式:
水平居中、垂直居中。
Flip用于水平反方向显示控件及窗口标题。
SizetoContent命令根据内容决定控件的大小,例如,按钮的大小由按钮上的显示文本决定。
图6-8 Layout下拉菜单
通过上面几个菜单项的操作能够很方便地齐整控件的摆放位置。
现在我们可以整理一下IDD_DIALOG1中摆放凌乱的控件:
(1)确定第一个和最后一个StaticText控件的位置,同时选中5个StaticText控件,执行菜单命令Layout->
MakeSameSize-width
(2)执行菜单命令Layout->
Align-Bottom,水平对齐5个控件。
(3)执行菜单命令Layout->
SpaceEvenly-Across,使5个控件水平等间距。
(4)选择“哲学”,执行菜单命令Layout->
SizetoContent,微调控件位置
(5)确定第一个和最后一个StaticText控件的位置,同时选中5个StaticText控件,执行菜单命令Layout->
Align->
Bottom和Layout->
SpaceEvenly->
Across。
操作完毕,可以看到控件整齐地排放在对话框模板上,如图6-9所示。
图6-9 EX6对话框设计_整理控件
在Windows环境中通常提供两种操作方法,鼠标操作方式和键盘操作方式,使用鼠标可以直接点击控件进行访问,使用键盘访问控件需要通过Tab键顺次找到某个控件。
TabOrder规定了使用Tab键访问控件的顺序,一般TabOrder是控件生成的顺序,执行菜单命令Layout->
TabOrder可以显示并修改TabOrder,对IDD_DIALOG1执行菜单命令TabOrder如图6-10所示。
图6-10 显示TabOrder
改变TabOrder的方法既简单又直观,执行了TabOrder命令出现了顺序号之后,按你所想要的访问顺序依次点击每一个控件,完成后,点击空白处就可以了。
读者可以试练习将上图的Tab顺序变成先访问第一个EditBox,访问完所有的EditBox后再访问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设计对话框类
一个对话框资源要加入到一个窗口应用程序中,首先要为它创建一个对话框类,是CDialog类的派生类。
应用程序运行时,窗口操作系统使用对话框类为对话框在内存开辟空间。
在Win32API类型的窗口应用程序中,都是直接通过控件ID来访问对话框上的控件的,而MFC提供了连接变量来标识控件,连接变量是对话框的成员变量,同时对话框类有一套交换和验证数据的方式。
6.3.1创建对话框类
创建对话框类的步骤如下:
1.保存已创建好的对话框模板。
2.确保新的对话框资源在对话框编辑器中打开状态下,打开ClassWizard窗口。
打开ClassWizard的方式有3种:
(1)窗口菜单命令View->
ClassWizard
(2)快捷菜单命令ClassWizard
(3)快捷键:
Ctrl+w
3.在弹出的AddingaClass对话框中,如图6-12所示,选择Createanewclass单选钮,单击OK按钮。
图6-12 “增加类”对话框
4.在随后弹出的NewClass对话框中,如图6-13所示,只需填写类的名称:
CScoreDlg,单击OK按钮。
关闭ClassWizard,对话框类的创建就完成了。
填写类名
图6-13 填写新类名称
在Workspace窗口的ClassView面板中,可以看到增加了一个新的类CScoreDlg,选择FileView面板,在HeaderFiles和SourceFiles文件夹中,可以看到该类的头文件和实现文件,文件名是类名除去开头的类标志“C”。
图6-14 新增对话框类及文件
在创建新类的时候,要注意新类的对话框ID一定要与对话框资源ID一致,这些ID告诉对话框类,在对话框窗口创建前,哪一个对话框资源要被检查,初始化控件并显示。
尤其在创建好对话框后,不能随意地改动对话框资源ID和删除对话框资源。
6.3.2创建对话框成员变量
创建好一个对话框类后,可以增加类的成员变量来操作对话框上的控件。
出于不同的操作目的,MFC提供了两种类型的成员变量,如表6-1所示。
表6-1 对话框类的成员变量类型
类型
描述
Values
值类型的成员变量。
用于控件的值控制,可以有多种数据类型,由所连接的控件类型决定。
例如,EditBox控件可以有CString型或int型。
Radio Button可以是int型。
Controls
控件类型的成员变量,实质是该控件类的一个对象。
创建了一个控件对象,就可以通过该对象使用控件类的方法对控件进行操作,例如,在程序运行时为ComboBox加入选择项,设置控件是否有效或可见等。
例如,创建了CScoreDlg类后,需要为对话框中每一个EditBox控件创建一个值类型的成员变量,来取得用户在EditBox输入的数据,增加控件成员变量的步骤如下:
(1)打开ClassWizard窗口,选择MemberVariables标签页,Classname下拉列表中选择CScoreDlg类。
这时,对话框中可以创建成员变量的控件ID出现在下方的ControlIDs列表中,如图6-15所示。
图6-15 增加一个对话框类的成员变量
(2)选择一个IDC_SCORE1,单击AddVariable按钮,弹出AddMemberVariable对话框,Membervariablename编辑框中填写变量名为:
m_score1,确认Category下拉框中为:
Value,在Variabletype下拉框中选择为:
int。
(3)单击OK按钮,回到ClassWizard窗口,可以看到新增的成员变量出现在列表中。
同样的操作增加其它四个成员变量。
(4)如果增加成员变量时操作有误,例如变量名错误,变量类型错误,选择该成员变量,单击DeleteVariable按钮删除该变量,再重新创建。
创建好的成员变量如图6-16所示。
变量类型
变量名称
图6-16 成员变量列表
创建好成员变量后,我们来检查一下ClassWizard作了哪些工作:
(1)展开项目工作区的ClassView面板中的CScoreDlg类,在树目录上出现了刚创建的成员变量。
(2)双击CScoreDlg的类名,进入该类的头文件ScoreDlg.h,可以找到对话框类定义的代码,如程序清单6-1中所示。
程序清单6-1:
对话框成员变量定义示例
classCScoreDlg:
publicCDialog
{
//Construction
public:
CScoreDlg(CWnd*pParent=NULL);
//standardconstructor
//DialogData
//{{AFX_DATA(CScoreDlg)
enum{IDD=IDD_DIALOG1};
intm_score1;
intm_scroe2;
intm_score4;
intm_score5;
intm_score3;
//}}AFX_DATA
......
}
其中呈灰色显示的,在宏“{{AFX_DATA(CScoreDlg)......}}AFX_DATA”之间定义的是用ClassWizard创建的成员变量。
需要注意的是,所有ClassWizard产生的灰色显示的代码,不要在文件中直接修改,而应在ClassWizard工具中进行修改,不然容易引起错误。
(3)打开该类的构造函数,可以看到ClassWizard自动加入了成员变量的初始化代码,如程序清单6-2所示。
程序清单6-2:
对话框类的构造函数
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_INIT
6.3.3对话框数据交换和校验
对话框的值类型的成员变量存储了与控件相对应的数据,对框话打开时,用户可以修改控件的数据,有时需要应用程序对用户的输入进行及时反馈,这时数据成员变量需要与控件交换数据,以完成输入输出功能。
对于这种功能MFC是靠CDataExchange类提供的数据交换(DDX:
DialogDataExchange)机制来完成的,该类提供了数据有效机制(DDV:
DialogDataValidation)
当在对话框类中增加一个数据成员变量,有时需要规定数据的有效性校验规则,例如,成绩录入对话框中,应设置各门课的成绩应在0-100的范围内。
在应用程序运行的时候,当用户输入数据拷贝到数据成员变量时,DDV机制被调用,如果有效性校验失败,即用户输入一个不合理的数据时,将出现一个错误信息对话框,并返回到出现错误输入的控件。
有效性校验的设置也是在ClassWizard中完成的。
我们再回到成绩录入的MemberVariables标签页,选择表示成绩输入框的m_score1,在标签页的下方会出最大值和最小值的输入框,如图6-17所示,填入0和100。
如果一个CString型的数据成员变量对应的通常是字符串的长度。
图6-17 添加数据成员变量的有效范围
对话框类调用DoDataExchange函数来实现DDV和DDX,对应图6-17的CScoreDlg类的DoDataExchange代码如程序清单6-3所示。
程序清单6-3:
对话框类的DoDataExchange函数
voidCScoreDlg:
DoDataExchange(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);
DDX_Control(pDX,IDC_SCORE2,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_MAP
pDX指针指向一个CDataExchange对象,DDX函数来完成控件和数据成员变量之间的数据交换,DDV完成数据有效性检查。
DDX和DDV适用于文本框、复选框、单选按钮、列表框和组合框。
当程序需要交换数据时,不需要编写代码调用DoDataExchange函数,而应该调用CWnd:
UpdateData()函数,UpdateData()函数内部调用了DoDataExchange函数。
UpdateData()函数只有一个BOOL类型的参数,决定数据交换的方向:
(1)UpdateData(false)
将对话框对象的数据成员变量的值拷贝到对话框中的控件。
(2)UpdateData(true)
将对话框中控件的值拷贝到对话框对象的数据成员变量。
你可以随时在需要进行数据交换时调用相应的UpdateData()函数,例如,在成绩录入的对话框中增加两个控件,一个是EditBox用于显示总分,另一个是Button用于计算总分,则在Button的Click事件处理函数中,就需要先调用UpdateData(true)获取用户录入的5门功课的成绩,在计算总分后,调用UpdateData(false),将总分显示在EditBox中。
在默认的CDialog:
OnInitDialog()函数中调用了UpdateData(false),这样在对话框创建的时候,数据成员的初值就会反映到相应的控件上。
若用户单击OK(确定)按钮关闭对话框,CDialog:
OnOK()函数会调用UpdateData(true),将控件中的数据传给数据成员变量,如图6-18所示。
图中说明了对话框的控件与对话框对象之间的数据交换是由框架自动完成的,而对话框对象与文档对象之间的数据交换则需要编写代码。
图6-18 数据交换和验证在应用程序中的实现
6.4运行对话框
创建好一个对话框资源和对话框类,要在应用程序中运行对话框,通常要在一个菜单命令下打开一个对话框。
所以,首先要定义一个菜单项和相应的菜单命令处理函数,在函数中编写代码运行对话框。
运行模式对话框和无模式对话框有所不同,下面结合实例详细介绍两种对话框运行的方法。
6.4.1模式对话框
在应用程序中使用得更多的还是模式对话框,模式对话框的运行分两个步骤:
(1)创建一个对话框对象
(2)调用CDialog:
DoModal()函数打开对话框
DoModal()函数负责模式对话框的创建和撤消。
在创建对话框时,DoModal()的任务包括:
装载对话框资源、调用OnIn