与对话框编程教学.ppt

上传人:牧羊曲112 文档编号:6237314 上传时间:2023-10-08 格式:PPT 页数:161 大小:507.50KB
返回 下载 相关 举报
与对话框编程教学.ppt_第1页
第1页 / 共161页
与对话框编程教学.ppt_第2页
第2页 / 共161页
与对话框编程教学.ppt_第3页
第3页 / 共161页
与对话框编程教学.ppt_第4页
第4页 / 共161页
与对话框编程教学.ppt_第5页
第5页 / 共161页
点击查看更多>>
资源描述

《与对话框编程教学.ppt》由会员分享,可在线阅读,更多相关《与对话框编程教学.ppt(161页珍藏版)》请在三一办公上搜索。

1、第五章 MFC 与对话框编程,5.1 对话框的基本原理 对话框是 Windows 应用程序 GUI 界面的一个重要组成部分,它的主要功能:接收用户的输入(数据和操作、控制命令);输出用户关心的状态信息(操作的结果数据和状态)。在对话框中,可以放置各种必要的控件,所有与用户的交互 操作都是通过这些控件实现的。在 MFC 中,对话框的基本属性和行为由 CDialog 类描述,该类的基类为 CWnd,因此,它继承了窗口类的所有属性和功能,并且增加了交互操作所需要的数据交换特性。放置在对话框中的各类控件,MFC 都有相应的类来描述,所有控件类的基类都是 CWnd。CDialog 类和所有控件类的派生层

2、次结构如下:,由此我们可以看出:对话框可以视为是提供了一个能放置多个子窗口,并提供了窗口之间通讯操作的窗口框架。这种异类同构的结构有利于简化构造和便于通讯。,CObject,对话框和放置在其中的控件的创建,MFC 应用程序是从两个方面实现的:对话框模板资源:描述对话框本身和各个控件的类型、外观 属性和控件在对话框中的分布信息。使用资源编辑器绘制模 板,并将相关的信息保存在资源文件(扩展名为“.rc”)中。对话框类:封装对话框的属性和操作功能。保存在相应的定 义和实现文件中。注意,与所有 CWnd 及其派生类对象一样,对话框类对象必须与对话框模板所描述的 Windows 窗口相关联后,所有施加于

3、对话框的操作才是合法的。,对话框的设计步骤一般是先设计对话框模板,然后定义与对话框模板资源相关联的对话框类。对话框的使用分为模态对话框和非模态对话框两种:模态对话框:对话框打开时,用户只能在对话框中进行交互 操作,只有对话框关闭后,才能进行其他用户界面的操作。非模态对话框:打开对话框进行操作的同时,仍然可以进行 其他用户界面的交互操作。,5.2 创建模态对话框 创建一个名为“Register”SDI 应用程序,用于人员信息的注册登记。该应用程序项目除视图的基类选择 CEditView 外,其他均接受缺省选择。5.2.1 创建对话框模板资源 为项目添加一个对话框模板(缺省命名为 IDD_DIAL

4、OG1)。从控件选择面板上选择所需要的控件,将它放置到对话框模板中你所希望的设计位置上。对话框和对话框中的每个控件都可以通过“属性”对话框设置它们的属性和风格。选中对话框或某个控件,点击鼠标右键便会弹出一个浮动上下文菜单:,选择菜单项 Properties,便弹出选中对话框或控件的属性操作对话框:,操作选择标签的个数和类型随着选中的对象(对话框或不同控件)的不同而不同,但其中最右边的两个按钮和第一项标签是相同的。1 按钮:按下该按钮,使按钮变成,使得该属性对话框 保持可见(Keep Visible),直到释放该按钮或强制关闭对话框。属性对话框的内容会随着当前选中对象的改变而变化。2 按钮:点击

5、该按钮,将显示当前选中属性页面相关内容的 帮助信息。,3 通用标签:提供对话框或所有控件的通用属性操作。对话框的主要通用属性操作:ID指定对话框的标识值,程序可使用它装载对话框资源和选取对话框窗口。Caption指定对话框的显示标题。Font选择对话框中所有文本(包括控件标题)字体。Menu如果需要,可为对话框选择显示菜单资源。控件的通用属性的含义如下:ID指定控件的标识值,程序使用它装载控件资源和选取控件窗口。,Caption指定诸如静态文本、组框、按钮、复选框、单选按钮等控件的显示标题。对于能发出通知消息的控件,其标题与菜单项标题一样,紧跟字符&之后的字符在运行时具有下划线,可通过按Alt

6、+下划线字符替代点击该控件。Visible指定控件被创建后是否可见。Disable指定控件被创建后是处于允许还是被禁止使用。Tab stop对话框运行时,允许用户使用Tab 键顺序选中具有该属性的控件。控件选中顺序可以任意指定。,Group用来指定一组控件(例如单选按钮),用户可以用箭头键在组内的控件之间移动选择;在同一组内的单选按钮具有互斥性,即只能选中一个单选按钮。如果一个控件具有Group 属性,则这个控件以及按Tab 顺序紧随其后的的所有控件都属于同一组,直到另一个有Group 属性的控件为止。本例中对话框的具体设计步骤如下:1 修改对话框模板资源的标识为 IDD_REGISTER。2

7、 在对话框中添加控件,3 设置控件的 Tab 顺序4 测试对话框效果,对话框类的创建 使用 ClassWizard 创建与对话框模板资源 IDD_REGISTER 相关联的对话框类 CRegisterDialog,其基类为 CDialog。为对话框类加入成员变量 对话框的主要功能就是要完成数据信息的输入输出,用户通过控件输入的数据信息需要存放在相应的数据对象中,才能被程序读取使用;程序通过控件输出的数据信息也需要先存储到相应数据对象中,才能被送到对应的控件显示。,这些数据对象相当于控件与用户或程序之间交换数据信息的缓冲区,所以在对话框类中增加与对话框模板中控件对应的数据对象是必要的。控件所对应

8、的数据对象有两类:一类是控件所对应的 MFC 类对象(控件类对象)可以用于对 控件的功能的调用;另一类是数值类对象,用于数据信息的交换。常用控件所对 应的数值类对象如下:,为控件定义哪一类数据对象,或是两类数据对象都定义将根据控件在对话框类中的使用情况而定。具体的添加方法:在 Visual C+6.0 中,使用 ClassWizard 的Member Variables属性页完成。添加方法如下:,在对话框中选中要添加数据对象的控件 ID,双击被选项或点击 按钮,弹出“Add Member Variable”对话框:,在该对话框中可以确定你所要添加的数据对象的种类是数值类对象还是控件类对象,并为

9、所添加数据对象命名(推荐命名规则:m_+数据对象类型缩写+数据对象含义,例如 m_nWork)。本例在 CRegisterDialog 中增加的数据对象如下:,在 Visual C+.NET 中,是通过在对话框模板中,为每个需要添加对象成员的方法实现的。具体的添加方法如下图所示:,对话框的初始化 对话框初始化是在对话框类构造函数和对话框窗口初始化成员函数 OnInitDialog 中完成的。构造函数只完成数据成员的初始化,因为此时对话框类对象 正在创建中,而对话框窗口还未创建,窗口句柄无效。如果 需要初始化的数据对象是通过 ClassWizard 的 Member Variables 页添加的

10、,则构造函数中数据对象的初始化代码将会由 ClassWizard 自动添加(当然可以根据需要修改这些代码)。例如:,CRegisterDialog:CRegisterDialog(CWnd*pParent/*=NULL*/):CDialog(CRegisterDialog:IDD,pParent)/AFX_DATA_INIT(CRegisterDialog)m_nAge=0;m_strIncome=_T();m_strKind=_T();m_bMarried=FALSE;m_strName=_T();m_nSex=-1;m_strUnit=_T();m_nWork=-1;/AFX_DATA_I

11、NIT,OnInitDialog 虚函数是窗口消息 WM_INITDIALOG 的响应函数。当对话框对象收到此消息时,对话框窗口已创建完成,对话 框窗口句柄已经有效,但对话框还没有被显示,对话框窗口 中的控件也已被创建。这意味着在重新定义的 OnInitDialog 中 可以添加一些影响对话框(包括控件)外观的初始化和对话 框构造函数无法完成的初始化工作。OnInitDialog 对对话框的 作用与 OnCreate 对 CMainFrame 对象的作用类似。本例中,首 先使用 ClassWizard 为 CRegisterDialog 添加对 WM_INITDIALOG 消息映射和处理函数

12、OnInitDialog(注意,在 Visual C+.NET 中 是通过重载基类的虚函数 OnInitDialog 的方法完成的),然后 手工在 OnInitDialog 中加入对用于工资收入的列表框控件的初 始化代码如下:,BOOL CRegisterDialog:OnInitDialog()CDialog:OnInitDialog();/TODO:Add extra initialization here m_ctrlIncome.AddString(500元以下);m_ctrlIncome.AddString(500-1000元);m_ctrlIncome.AddString(1000

13、-2000元);m_ctrlIncome.AddString(2000元以上);return TRUE;/return TRUE unless you set the focus to a control/EXCEPTION:OCX Property Pages should return FALSE,信息交换、验证 在对话框操作时,用户只要通过交互方式修改对话框窗口某个控件中的数据信息,就可以修改与该控件关联数值对象的值;反过来只要程序修改了对话框类对象中某个与控件关联数值对象的值,也就可以修改对话框窗口中与该数值对象关联控件中显示的信息。对话框的这种数据交换(DDX)和数据有效验证(DDV

14、)能力是由 MFC 类 CDataExchange 来实现的。实现这种信息交换操作是由虚函数 CDialog:DoDataExchange完成的。派生类中该函数的重定义版本将在调用该函数的基类版本基础上完成派生类对象所需要的特定的数据交换操作。所幸的是该函数的重定义工作可以借助 ClassWizard 在定义与控件相关的对话框类数据对象的同时自动完成的。例如在本例中:,void CRegisterDialog:DoDataExchange(CDataExchange*pDX)CDialog:DoDataExchange(pDX);/AFX_DATA_MAP(CRegisterDialog)DD

15、X_Control(pDX,IDC_INCOME,m_ctrlIncome);DDX_Text(pDX,IDC_AGE,m_nAge);DDV_MinMaxUInt(pDX,m_nAge,0,150);DDX_LBString(pDX,IDC_INCOME,m_strIncome);DDX_CBString(pDX,IDC_KIND,m_strKind);DDV_MaxChars(pDX,m_strKind,15);DDX_Check(pDX,IDC_MARRIED,m_bMarried);DDX_Text(pDX,IDC_NAME,m_strName);,DDV_MaxChars(pDX,m

16、_strName,15);DDX_Radio(pDX,IDC_SEX,m_nSex);DDX_Text(pDX,IDC_UNIT,m_strUnit);DDV_MaxChars(pDX,m_strUnit,30);DDX_Radio(pDX,IDC_WORK,m_nWork);/AFX_DATA_MAP,由于对话框的数据交换是双向的,所以参数 pDX 所指向的CDataExchange 类对象含有数据的传递方向。实现数据交换不是直接调用 DoDataExchange(因为无法确定数据传递方向),而是调用 CWnd:UpdateData。UpdateData 的原型如下:BOOL UpdateD

17、ata(BOOL bSaveAndValidate=TRUE);参数:bSaveAndValidate=TRUE 指定数据值从控件传递到数据对象;bSaveAndValidate=FALSE 指定数据值从数据对象传递到控件。该函数调用了 DoDataExchange,显然,参数 bSaveAndValidate 确定了 DoDataExchange 的数据传递方向。,对话框的运行在程序中运行模态对话框的步骤:在栈上构建一个局部对话框类对象。调用CDialog:DoModal()DoModal 负责模态对话框的创建启动一个消息循环撤消 对话框(接收到 按钮或 按钮控件发出的消 息)。显然,在 D

18、oModal 函数返回之前,不可能进行其他界 面上的操作的。该函数是一个虚函数,意味着可以根据需要 在 CDialog 的派生类中定义特定功能的 DoModal,但大多数 情况下无须重新定义。对话框创建时,程序框架会自动调用 OnInitDialog 初始化 对话框,并调用 UpdateData(FALSE)初始化控件的显示。,对话框撤消时,分为两种情况:按 按钮,消息处理成员函数 OnOk 被调用。在该函数的执行中,首先调用 UpdateData(TRUE)将控件中的数据传递到相应数据对象中保存起来,然后调用 EndDialog 关闭对话框,并返回标志值 IDOK。按 按钮,消息处理成员函数

19、 OnCancel 被调用,在该函数的执行中,只调用 EndDialog 关闭对话框,并返回标志值 IDCANCEL。根据 DoModal 返回的标志值,程序就可以知道对话框是如何 结束的(按 或 按钮),从而确定后续操作。,在本例中,为了模态使用对话框,添加了一条菜单命令来触发对话框类对象的创建,对话框的模态创建、显示、操作和根据对话框结束状态的后续操作。1 在菜单资源中的 Edit 弹出式菜单中添加菜单项“登录数据”,其标识为 ID_EDIT_REGISTER。2 使用 ClassWizard 为菜单项“登录数据”在视图类 CRegisterView 中定义命令消息映射项和处理函数 OnE

20、ditRegister。3 定义函数 OnEditRegister 实现代码:,void CRegisterView:OnEditRegister()/TODO:Add your command handler code here CRegisterDialog dlg;if(dlg.DoModal()=IDOK)CString str;GetWindowText(str);/获取视图窗口原有文本内容 str+=rn;str+=姓名:;str+=dlg.m_strName;str+=rn;str+=性别:;str+=dlg.m_nSex?女:男;str+=rn;str+=年龄:;CString

21、 str1;str1.Format(%d,dlg.m_nAge);,str+=str1;str+=rn;str+=婚否:;str+=dlg.m_bMarried?已婚:未婚;str+=rn;str+=就业情况:;str+=dlg.m_nWork?下岗:在职;str+=rn;str+=工作单位:;str+=dlg.m_strUnit;str+=rn;str+=单位性质:;str+=dlg.m_strKind;str+=rn;str+=工资收入:;str+=dlg.m_strIncome;str+=rn;SetWindowText(str);/在视图窗口中显示新文本 4 在 CRegisterVi

22、ew 的实现文件中加入:#include“RegisterDialog.h”5 编译运行,5.2.7 程序的改进 在程序的运行中发现存在这样的缺点:当在“就业情况”组框中选择了单选按钮“下岗”,而“单位情况”组框中的所有控件仍然有效,显然这是不合理的,会引起登录数据的错误。为了克服这一缺点,应该当在“就业情况”组框中选择了单选按钮时,程序能够响应对应的控件消息,在消息处理函数中根据所选按钮的不同,使“单位情况”组框中的相关控件允许或禁止。虽然组框中的单选按钮是两个,而它们的消息处理函数只需要一个,因此应该使用 ON_CONTROL_RANGE 消息映射宏进行消息映射。不幸的是 ClassWiz

23、ard 不支持 ON_CONTROL_RANGE,所以我们必须按下列步骤手工创建单选按钮的消息映射和消息处理函数。,1 在 CRegisterDialog 的定义文件中定义消息处理函数原型:class CRegisterDialog:public CDialog/Implementation protected:/Generated message map functions/AFX_MSG(CRegisterDialog)virtual BOOL OnInitDialog();/AFX_MSG afx_msg void OnWorkClicked(UINT nCmdID);DECLARE_M

24、ESSAGE_MAP();,2 在 CRegisterDialog 实现文件的消息映射表中加入映射条目:BEGIN_MESSAGE_MAP(CRegisterDialog,CDialog)/AFX_MSG_MAP(CRegisterDialog)/AFX_MSG_MAP ON_CONTROL_RANGE(BN_CLICKED,IDC_WORK,IDC_WORK1,OnWorkClicked)END_MESSAGE_MAP(),3 在 CRegisterDialog 实现文件中添加消息响应函数实现代码:void CRegisterDialog:OnWorkClicked(UINT nCmdID)

25、if(IsDlgButtonChecked(IDC_WORK)/选中“在职”单选按钮否?/使“单位情况”组框中的相关控件有效 GetDlgItem(IDC_UNIT)-EnableWindow(TRUE);GetDlgItem(IDC_KIND)-EnableWindow(TRUE);m_ctrlIncome.EnableWindow(TRUE);,else/清除文本框内容,并使之禁止 GetDlgItem(IDC_UNIT)-SetWindowText();GetDlgItem(IDC_UNIT)-EnableWindow(FALSE);/使组合框处于未选择状态,并使之禁止 CComboBo

26、x*pComboBox=(CComboBox*)GetDlgItem(IDC_KIND);pComboBox-SetCurSel(-1);pComboBox-EnableWindow(FALSE);/使列表框为未选和禁止状态 m_ctrlIncome.SetCurSel(-1);m_ctrlIncome.EnableWindow(FALSE);,在对话框中获取控件对象并对其控制操作有两种方法:直接使用与控件关联的控件对象,本例中对“工资收入”列表 框控件的操作是通过与 CListBox 对象 m_ctrlIncome 进行的。利用 CWnd 类的一组操作对话框控件的成员函数,本例中对 于“工作

27、单位”文本框和“单位性质”组合框控件的操作就是调 用 CWnd:GetDlgItem(int nID)返回指向标识值为 nID 的控件对 象的指针,调用代码如下:CEdit*pUnit=(CEdit*)GetDlgItem(IDC_UNIT);CComboBox*pKind=(CComboBox*)GetDlgItem(IDC_KIND);从而借助该指针对相应的控件进行操作。4 编译运行(应用程序项目“Register1”),5.3 非模态对话框5.3.1 非模态对话框的特点 非模态对话框的设计与模态对话框基本类似,也是由对话框模板资源设计和对话框类设计两部分组成。但在对话框的创建和删除过程中

28、,两类对话框存在下列差异:1 对话框模板的 Visible 属性不同非模态对话框模板应该具有 Visible 属性,否则对话框创建时 将不能自动可见。当然,如果对话框模板没有设置 Visible 属 性,可以在对话框创建后调用 CWnd:ShowWindow(SW_SHOW)显示对话框。模态对话框则不必设置 Visible 属性,因为 DoModal 函数隐含 解决了对话框的可见性。,2 创建空间不同非模态对话框类对象是使用 new 操作符在堆中动态创建的,并在该对话框对象的所属类中增加该对话框类指针,用于指 向动态创建的对话框类对象。模态对话框一般是以局部对象的形式构建在堆栈上。3 窗口创建

29、函数不同非模态对话框的创建是调用 CDialog:Create 函数创建的,该函 数不启动新的消息循环,因此,所创建的对话框与应用程序 使用同一个消息循环。模态对话框调用 CDialog:DoModal 完成对话框窗口的创建、启 动消息循环和撤消。,4 窗口删除函数不同非模态对话框类必须编写自己的 OnOK 和 OnCancel 函数,以 便在函数中调用 CWnd:DestroyWindow 关闭对话框。模态对话框通过默认的 CDialog:OnOK 和 CDialog:OnCancel 调用 CDialog:EndDialog 关闭对话框。注意,DoModal、OnOk 和 OnCancel

30、 都是虚函数,这意味着如果需要,可以在派生类 中重新定义这些函数的特定版本,完成特定的附加工作。5 清理对话框对象的方式不同非模态对话框对象应在不再使用时,使用 delete 操作符删除 在堆中动态创建的对话框对象。由于一个窗口被删除后,框 架会自动调用虚函数 CWnd:PostNcDestroy,因此可以在该函 数的重定义版本中使用 delete 删除窗口的关联对话框对象。模态对话框类对象是局部的,因此不需要显式删除。,6 非模态对话框不能“重入”非模态对话框必须通过对指向对话框对象的指针的检查,来 判别对话框对象是否已经创建,如果未创建,则创建对话框 对象;否则只需激活已经创建的对话框,而

31、不要重新创建。模态对话框是局部对象,每次调用都重新在栈上构建。根据上述两种对话框的不同,修改“Register1”应用程序,将数据登录对话框改为无模式对话框,项目名为“Register2”。修改步骤如下:,修改对话框模板的 Visible 属性有效,并将 和 按钮的显示标题改为 和。,在 CRegisterView 类定义中加入数据登录对话框类指针:public:CRegisterDialog*m_pRegisterDlg;注意将 CRegisterDialog 类的头文件包含在 CRegisterView 类的 定义文件中,或在定义对话框指针之前加入超前声明:class CRegisterD

32、ialog;,在 CRegisterDialog 类中增加 CWnd 类型的指针数据成员,用 于保存其父窗口对象的指针(以便与父窗口进行联系),并在构造函数中对该指针进行设置。protected:CWnd*m_pParent;CRegisterDialog:CRegisterDialog(CWnd*pParent/*=NULL*/):CDialog(CRegisterDialog:IDD,pParent)/AFX_DATA_INIT m_pParent=pParent;,修改 CRegisterView 类构造函数和消息处理函数:CRegisterView:CRegisterView()/TO

33、DO:add construction code here m_pRegisterDlg=NULL;void CRegisterView:OnEditRegister()/TODO:Add your command handler code hereif(m_pRegisterDlg)/判断对话框已创建否?m_pRegisterDlg-SetActiveWindow();/激活已创建的对话框 else m_pRegisterDlg=new CRegisterDialog(this);/创建对话框对象m_pRegisterDlg-Create(IDD_REGISTER,this);/创建窗口,使

34、用 ClassWizard 为 CRegisterDialog 类添加 OnCancel、OnOK 消息响应函数和重载虚函数 PostNcDestroy,并为这两个函数 编写定义代码:void CRegisterDialog:OnCancel()/TODO:Add extra cleanup here m_pParent-SendMessage(WM_DIALOG_DESTROY,0,0);/向父窗口发出关闭对话框消息 DestroyWindow();/关闭对话框窗口,void CRegisterDialog:OnOK()/TODO:Add extra validation here CStr

35、ing str;UpdateData();m_pParent-GetWindowText(str);/获取父窗口中的显示文本/在原来文本的基础上添加新文本 str+=rn;str+=姓名:;str+=m_strName;str+=rn;str+=性别:;str+=m_nSex?女:男;str+=rn;str+=年龄:;CString str1;,str1.Format(%d,m_nAge);str+=str1;str+=rn;str+=婚否:;str+=m_bMarried?已婚:未婚;str+=rn;str+=就业情况:;str+=m_nWork?下岗:在职;str+=rn;str+=工作单

36、位:;str+=m_strUnit;str+=rn;str+=单位性质:;str+=m_strKind;str+=rn;str+=工资收入:;str+=m_strIncome;str+=rn;m_pParent-SetWindowText(str);/在父窗口中显示添加后的文本 void CRegisterDialog:PostNcDestroy()/TODO:Add your specialized code here and/or call the base class delete this;/删除对话框类对象 CDialog:PostNcDestroy();,对话框关闭时要求其父窗口类

37、对象能及时将指向对话框的指 针设置为 NULL。实现方法和步骤如下:在 CRegisterDialog 的定义文件中增加用户自定义消息:const WM_DIALOG_DESTROY=WM_USER+100;在 CRegisterView 定义中增加消息处理函数声明:afx_msg LRESULT OnDialogDestroy(WPARAM,LPARAM);在 CRegisterView 实现文件中添加消息响应函数定义代码:LRESULT CRegisterView:OnDialogDestroy(WPARAM wParam,LPARAM lParam)m_pRegisterDlg=NULL

38、;return 1;编译运行,5.3.2 关于窗口对象的自动清除1 MFC 窗口类对象的组成 一个 MFC 窗口由两部分组成:描述窗口属性和功能的 C+类 窗口类(CWnd 或CWnd 的派生类)。Windows 窗口,该窗口的句柄作为一个数据成员 m_hWnd被封装在窗口类中。2 MFC 窗口类对象的创建 首先创建窗口的窗口类对象;然后调用窗口类的创建函数(例如 CWnd:Create)创建由参数确定的 Windows 窗口,并使之与窗口类对象相关联;或调用Windows 窗口关联函数(例如 CWnd:Attach)使窗口类对象与一个已经存在的 Windows 窗口相关联。,3 MFC 窗口

39、类的删除 先调用 CWnd:DestroyWindow 撤消 Windows 窗口,并使窗口类 对象的 Windows 窗口句柄属性 m_hWnd=NULL(表示窗口已 经无效)。一般情况下,该函数不需要直接调用,而是由应 用程序框架自动调用,例如:关闭窗口的 WM_CLOSE 消息、对话框的 或 按钮发出的消息都会导致该函数 被调用。如果 DestroyWindow 所撤消的窗口拥有子窗口,则 先删除所有的子窗口,然后删除父窗口。,然后删除窗口的窗口类对象。删除窗口类对象分两种情况:构建在堆栈上的窗口窗口类对象:该窗口类对象是作为某 个类的数据成员或函数中的局部变量。它们的生存期总是 有限的

40、,随着拥有窗口类对象的撤消或函数的返回,被自 动被删除,所以不必关心这类窗口类对象的删除。创建在堆上的窗口类对象:该窗口类对象是使用运算符 new 创建的,其生存期是任意的,因此,在关闭 Windows窗口后必须使用运算符 delete 从堆中删除窗口类对象,否则不会被自动清除。,4 自动清除功能 自动清除功能是指在 Windows 窗口被删除时,自动删除窗口 类对象。这是因为当 CWnd:DestroyWindow 被调用撤消一个 Windows 窗口时,与该窗口关联的窗口类对象的成员函数 PostNcDestroy 被调用。该函数是一个虚函数,MFC 所提供的 有些 CWnd 的派生类重定

41、义了该函数,在新版本函数中通过 代码 delete this 来删除与被撤消窗口关联的窗口类对象本身,因此不需要显式使用 delete 删除窗口类对象,即自动清除功 能。具有自动清除功能的 MFC 窗口类有:主框架窗口类(基类为 CFrameWnd)视图类(基类为 CView),这些窗口类的对象在应用程序中一般都是动态在堆中创建 的。而对于其他 MFC 窗口类的使用,由于大多数情况下是在 堆栈中创建的。所以 MFC 没有为这些类提供自动清除功能。这些窗口类包括:所有标准的 Windows 控件类 从 CWnd 直接派生的自定义窗口类(如用户定制的控件)切分窗口类 CSplitterWnd 默认

42、的控制栏类(如工具栏和状态栏)对话框类(从 CDialog 派生),由此可见,要不要为自己的派生窗口类添加自动清除功能,取决于所派生的窗口类的创建方法,例如,我们前面的非模 式对话框的实例中,由于对话框是在堆中创建的,要求其生 存期任意,所以需要为它添加了自动清除功能。否则我们必 须在对话框窗口被删除后,在对话框类对象的拥有者(父窗 口类对象)中的适当位置(如析构函数中),调用 delete 显式删 除对话框类对象。,5.4 创建属性表对话框 属性表是一种包含了多个对话框的对话框框架,这些包含在属性表中的对话框通常被称为属性页(Page)。每次只有一个属性页是可见的,在属性表的顶端有一行标签(

43、tab)用于指示属性表中不同的属性页,用户通过单击这些标签可以切换到不同的属性页。使用属性表可以按操作功能将控件分类放在不同的属性页中,便于组织和构造需要大量控件的复杂对话框,也使得对话框的使用界面更加友好。,5.4.1 属性表对话框的创建 属性表是由多个属性页和一个能放置这些属性页,并且将这些属性页关联起来的对话框框架组成的,就像是一个夹有多页文件的文件夹。为了支持属性表,MFC 提供了两个类:CPropertySheet:用于创建属性表框架和提供相应的属性和 操作。它的直接基类是 CWnd,使该类在窗口的属性和功能的 基础上增加了对属性页的创建、激活、切换、数据交换、撤 消等功能。CPro

44、pertyPage:用于创建属性表的属性页和提供相应的属性 和操作。它的直接基类是 CDialog,使该类在对话框的属性和 功能的基础上增加了对属性表框架各项管理的响应操作。,与普通对话框相比,属性表的设计和实现既有许多相似之处,又有一些不同。创建一个属性表一般包括以下几个步骤:1 创建属性页(对话框)资源 创建所有属性页的资源,每个属性页的资源都是一个对话框 模板。与创建普通对话框模板相比应注意以下几点:一般需要删除缺省的 和 按钮;每页的模板尺寸最好相同,如果不同,则在属性表创建时,系统会按最大的模板尺寸统一创建所有页的尺寸;指定标题(Caption)的内容将成为属性表中相应属性页的指示标

45、签内容;属性页模板属性设定为 TitleBar、Child、ThinBoder 和 Disable。,2 生成属性页类 使用 ClassWizard 为每个属性页模板定义相应的属性页类,基 类必须选择 CPropertyPage。3 在属性页类中为属性页中的控件添加关联的数据对象 与普通对话框一样,使用 ClassWizard 的Member Variables 属性页为每个属性页模板中的控件在相应的属性页类中添加 所需要的数据对象。,4 创建属性表创建属性表的方法两种:直接使用 CPropertySheet 类创建 在需要使用属性表的码段中加入相应的创建代码。例如:void CMyView:

46、DoModalPropertySheet()CPropertySheet propsheet;/创建属性表框架CMyFirstPage pageFirst;/创建第一属性页CMySecondPage pageSecond;/创建第二属性页pageFirst.m_nMember1=m_nMember1;/初始化第一属性页pageFirst.m_nMember2=m_nMember2;/初始化第一属性页pageSecond.m_nMember3=m_nMember3;/初始化第二属性页pageSecond.m_nmember4=m_nMember4;/初始化第二属性页,propsheet.AddP

47、age(,使用 CPropertySheet 类的派生类创建 一般步骤如下:使用 ClassWizard 定义一个 CPropertySheet 类的派生类;将所有属性页类对象以数据成员的形式加入到此派生类的 定义中;在此派生类构造函数中调用 CPropertySheet:AddPage 函数将各个属性页添加到属性表中,使得在属性表对象的创建操作自动包含了属性页的添加操作。在需要使用属性表的地方,使用此派生的属性表类创建特 定的属性表。,5.4.2 属性表的运行机制1 属性表初始化包括属性表框架的初始化和属性页的初始化。如果需要进行自定义初始化操作,属性表框架初始化应在重 定义的虚函数 CPr

48、opertySheet:OnCreate 中完成;而属性页初始 化应在重定义的虚函数 CPropertyPage:OnInitDialog 中完成。2 属性表的使用者一般调用 CPropertySheet:DoModal,按模态运 行方式创建属性表,并可通过判断 DoModal 的返回值(IDOK 或 IDCANCEL),确定关闭属性表的操作方式是“确认”还是“放弃”,从而确定后续操作。,3 模态运行的属性表会自动在属性表的底部提供三个按钮,依 次为 或、或 和 或 按钮(非模态运行的属性表不提供这些按钮)。其中:或 按钮的作用是确认当前属性页的操作,并关闭整个属性表。或 按钮的作用是放弃当前

49、属性页的操作,关闭整个属性表。通过标签的属性页切换操作将确认被切换属性页的操作。或 按钮的作用是确认当前属性页操作,并使属性表的所有操作生效,但不关闭该属性表。,对这三个按钮作出处理的响应函数可由 CPropertyPage 类提供 的消息响应函数 OnOK、OnCancel 和 OnApply(OnApply 会自 动调用 OnOK)完成。因此,我们可以在属性页派生类中重定 义这三个消息响应函数完成所需要的特定操作。应当指出:对属性页的这三个消息响应函数的调用并非直接 响应属性表的三个按钮的通知消息 BN_CLICKED 的结果,而 是通过 CPropertySheet 类或派生类对这三个按

50、钮的消息响应函 数,间接调用上述 CPropertyPage 的三个消息响应函数完成的。例如,定义响应 按钮的通知消息,完成特定的处理 可以有两种方法:,使用 ClassWizard 为属性表中任意一个属性页类重定义虚 函数 OnApply,在该函数中定义要实现的特定功能代码。一般情况下所定义的功能将对整个属性表起作用,所以 只须在一个属性页中重定义 OnApply 即可,不必为每个属 性页都重定义 OnApply。在 CPropertySheet 的派生类中添加 按钮的通知消 息 BN_CLICKED 的消息映射和响应函数,在该函数中定义 想要实现的操作。注意,系统为 按钮定义的标识 为 I

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号