与对话框编程教学.ppt_第1页
与对话框编程教学.ppt_第2页
与对话框编程教学.ppt_第3页
与对话框编程教学.ppt_第4页
与对话框编程教学.ppt_第5页
已阅读5页,还剩156页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

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

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

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

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

5、属性对话框的内容会随着当前选中对象的改变而变化。 2 按钮 :点击该按钮,将显示当前选中属性页面相关内容的 帮助信息,3 通用标签 :提供对话框或所有控件的通用属性操作。 对话框的主要通用属性操作: ID指定对话框的标识值,程序可使用它装载对话框 资源和选取对话框窗口。 Caption指定对话框的显示标题。 Font选择对话框中所有文本(包括控件标题)字体。 Menu如果需要,可为对话框选择显示菜单资源。 控件的通用属性的含义如下: ID指定控件的标识值,程序使用它装载控件资源和 选取控件窗口,Caption指定诸如静态文本、组框、按钮、复选框、单选 按钮等控件的显示标题。对于能发出通知消息的

6、 控件,其标题与菜单项标题一样,紧跟字符 m_strIncome = _T(); m_strKind = _T(); m_bMarried = FALSE; m_strName = _T(); m_nSex = -1; m_strUnit = _T(); m_nWork = -1; /AFX_DATA_INIT,OnInitDialog 虚函数是窗口消息 WM_INITDIALOG 的响应函数。 当对话框对象收到此消息时,对话框窗口已创建完成,对话 框窗口句柄已经有效,但对话框还没有被显示,对话框窗口 中的控件也已被创建。这意味着在重新定义的 OnInitDialog 中 可以添加一些影响对话

7、框(包括控件)外观的初始化和对话 框构造函数无法完成的初始化工作。OnInitDialog 对对话框的 作用与 OnCreate 对 CMainFrame 对象的作用类似。本例中,首 先使用 ClassWizard 为 CRegisterDialog 添加对 WM_INITDIALOG 消息映射和处理函数 OnInitDialog(注意,在 Visual C+ .NET 中 是通过重载基类的虚函数 OnInitDialog 的方法完成的),然后 手工在 OnInitDialog 中加入对用于工资收入的列表框控件的初 始化代码如下,BOOL CRegisterDialog:OnInitDialo

8、g() CDialog:OnInitDialog(); / TODO: Add extra initialization here m_ctrlIncome.AddString(500元以下); m_ctrlIncome.AddString(500-1000元); m_ctrlIncome.AddString(1000-2000元); m_ctrlIncome.AddString(2000元以上); return TRUE; / return TRUE unless you set the focus to a control / EXCEPTION: OCX Property Pages s

9、hould return FALSE,5.2.5 信息交换、验证 在对话框操作时,用户只要通过交互方式修改对话框窗口某 个控件中的数据信息,就可以修改与该控件关联数值对象的 值;反过来只要程序修改了对话框类对象中某个与控件关联数 值对象的值,也就可以修改对话框窗口中与该数值对象关联控 件中显示的信息。对话框的这种数据交换(DDX)和数据有效 验证(DDV)能力是由 MFC 类 CDataExchange 来实现的。 实现这种信息交换操作是由虚函数 CDialog:DoDataExchange 完成的。派生类中该函数的重定义版本将在调用该函数的基类 版本基础上完成派生类对象所需要的特定的数据交换

10、操作。所 幸的是该函数的重定义工作可以借助 ClassWizard 在定义与控件 相关的对话框类数据对象的同时自动完成的。例如在本例中,void CRegisterDialog:DoDataExchange(CDataExchange* pDX) CDialog:DoDataExchange(pDX); /AFX_DATA_MAP(CRegisterDialog) DDX_Control(pDX, IDC_INCOME, m_ctrlIncome); DDX_Text(pDX, IDC_AGE, m_nAge); DDV_MinMaxUInt(pDX, m_nAge, 0, 150); DDX

11、_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_strName, 15); DDX_Radio(pDX, IDC_SEX, m_nSex); DDX_Text(pDX, IDC_UNIT, m_strUnit); DDV_Max

12、Chars(pDX, m_strUnit, 30); DDX_Radio(pDX, IDC_WORK, m_nWork); /AFX_DATA_MAP,由于对话框的数据交换是双向的,所以参数 pDX 所指向的 CDataExchange 类对象含有数据的传递方向。实现数据交换不是 直接调用 DoDataExchange(因为无法确定数据传递方向),而 是调用 CWnd:UpdateData。UpdateData 的原型如下: BOOL UpdateData( BOOL bSaveAndValidate = TRUE ); 参数: bSaveAndValidate = TRUE 指定数据值从控件

13、传递到数据对象; bSaveAndValidate = FALSE 指定数据值从数据对象传递到控件。 该函数调用了 DoDataExchange,显然,参数 bSaveAndValidate 确 定了 DoDataExchange 的数据传递方向,5.2.6 对话框的运行 在程序中运行模态对话框的步骤: 在栈上构建一个局部对话框类对象。 调用CDialog:DoModal() DoModal 负责模态对话框的创建启动一个消息循环撤消 对话框(接收到 按钮或 按钮控件发出的消 息)。显然,在 DoModal 函数返回之前,不可能进行其他界 面上的操作的。该函数是一个虚函数,意味着可以根据需要 在

14、 CDialog 的派生类中定义特定功能的 DoModal ,但大多数 情况下无须重新定义。 对话框创建时,程序框架会自动调用 OnInitDialog 初始化 对话框,并调用 UpdateData(FALSE) 初始化控件的显示,对话框撤消时,分为两种情况: 按 按钮,消息处理成员函数 OnOk 被调用。在该函数 的执行中,首先调用 UpdateData( TRUE ) 将控件中的数据传 递到相应数据对象中保存起来,然后调用 EndDialog 关闭对 话框,并返回标志值 IDOK。 按 按钮,消息处理成员函数 OnCancel 被调用,在 该函数的执行中,只调用 EndDialog 关闭对

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

16、er 实现代码,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 += 年龄:; CStrin

17、g 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; S

18、etWindowText(str);/ 在视图窗口中显示新文本 4 在 CRegisterView 的实现文件中加入: #include “RegisterDialog.h” 5 编译运行,5.2.7 程序的改进 在程序的运行中发现存在这样的缺点:当在“就业情况”组框 中选择了单选按钮“下岗”,而“单位情况”组框中的所有控件仍 然有效,显然这是不合理的,会引起登录数据的错误。为了克 服这一缺点,应该当在“就业情况”组框中选择了单选按钮时, 程序能够响应对应的控件消息,在消息处理函数中根据所选按 钮的不同,使“单位情况”组框中的相关控件允许或禁止。虽然 组框中的单选按钮是两个,而它们的消息处理函

19、数只需要一 个,因此应该使用 ON_CONTROL_RANGE 消息映射宏进行消息 映射。不幸的是 ClassWizard 不支持 ON_CONTROL_RANGE,所 以我们必须按下列步骤手工创建单选按钮的消息映射和消息处 理函数,1 在 CRegisterDialog 的定义文件中定义消息处理函数原型: class CRegisterDialog : public CDialog / Implementation protected: / Generated message map functions /AFX_MSG(CRegisterDialog) virtual BOOL OnIni

20、tDialog(); /AFX_MSG afx_msg void OnWorkClicked(UINT nCmdID); DECLARE_MESSAGE_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 在 CRegi

21、sterDialog 实现文件中添加消息响应函数实现代码: void CRegisterDialog:OnWorkClicked(UINT nCmdID) if(IsDlgButtonChecked(IDC_WORK) / 选中“在职”单选按钮否? / 使“单位情况”组框中的相关控件有效 GetDlgItem(IDC_UNIT)-EnableWindow(TRUE); GetDlgItem(IDC_KIND)-EnableWindow(TRUE); m_ctrlIncome.EnableWindow(TRUE);,else / 清除文本框内容,并使之禁止 GetDlgItem(IDC_UNIT

22、)-SetWindowText(); GetDlgItem(IDC_UNIT)-EnableWindow(FALSE); / 使组合框处于未选择状态,并使之禁止 CComboBox *pComboBox = (CComboBox*)GetDlgItem(IDC_KIND); pComboBox-SetCurSel(-1); pComboBox-EnableWindow(FALSE); / 使列表框为未选和禁止状态 m_ctrlIncome.SetCurSel(-1); m_ctrlIncome.EnableWindow(FALSE);,在对话框中获取控件对象并对其控制操作有两种方法: 直接使用

23、与控件关联的控件对象,本例中对“工资收入”列表 框控件的操作是通过与 CListBox 对象 m_ctrlIncome 进行的。 利用 CWnd 类的一组操作对话框控件的成员函数,本例中对 于“工作单位”文本框和“单位性质”组合框控件的操作就是调 用 CWnd:GetDlgItem(int nID) 返回指向标识值为 nID 的控件对 象的指针,调用代码如下: CEdit *pUnit = (CEdit*)GetDlgItem(IDC_UNIT); CComboBox *pKind = (CComboBox*)GetDlgItem(IDC_KIND); 从而借助该指针对相应的控件进行操作。 4

24、 编译运行(应用程序项目“Register1”,5.3 非模态对话框 5.3.1 非模态对话框的特点 非模态对话框的设计与模态对话框基本类似,也是由对话框 模板资源设计和对话框类设计两部分组成。但在对话框的创建 和删除过程中,两类对话框存在下列差异: 1 对话框模板的 Visible 属性不同 非模态对话框模板应该具有 Visible 属性,否则对话框创建时 将不能自动可见。当然,如果对话框模板没有设置 Visible 属 性,可以在对话框创建后调用 CWnd:ShowWindow( SW_SHOW ) 显示对话框。 模态对话框则不必设置 Visible 属性,因为 DoModal 函数隐含

25、解决了对话框的可见性,2 创建空间不同 非模态对话框类对象是使用 new 操作符在堆中动态创建的, 并在该对话框对象的所属类中增加该对话框类指针,用于指 向动态创建的对话框类对象。 模态对话框一般是以局部对象的形式构建在堆栈上。 3 窗口创建函数不同 非模态对话框的创建是调用 CDialog:Create 函数创建的,该函 数不启动新的消息循环,因此,所创建的对话框与应用程序 使用同一个消息循环。 模态对话框调用 CDialog:DoModal 完成对话框窗口的创建、启 动消息循环和撤消,4 窗口删除函数不同 非模态对话框类必须编写自己的 OnOK 和 OnCancel 函数,以 便在函数中调

26、用 CWnd:DestroyWindow 关闭对话框。 模态对话框通过默认的 CDialog:OnOK 和 CDialog:OnCancel 调用 CDialog:EndDialog 关闭对话框。注意,DoModal、OnOk 和 OnCancel 都是虚函数,这意味着如果需要,可以在派生类 中重新定义这些函数的特定版本,完成特定的附加工作。 5 清理对话框对象的方式不同 非模态对话框对象应在不再使用时,使用 delete 操作符删除 在堆中动态创建的对话框对象。由于一个窗口被删除后,框 架会自动调用虚函数 CWnd:PostNcDestroy,因此可以在该函 数的重定义版本中使用 delet

27、e 删除窗口的关联对话框对象。 模态对话框类对象是局部的,因此不需要显式删除,6 非模态对话框不能“重入” 非模态对话框必须通过对指向对话框对象的指针的检查,来 判别对话框对象是否已经创建,如果未创建,则创建对话框 对象;否则只需激活已经创建的对话框,而不要重新创建。 模态对话框是局部对象,每次调用都重新在栈上构建。 根据上述两种对话框的不同,修改“Register1”应用程序,将数据 登录对话框改为无模式对话框,项目名为“Register2”。修改步 骤如下,修改对话框模板的 Visible 属性有效,并将 和 按钮的显示标题改为 和,在 CRegisterView 类定义中加入数据登录对话

28、框类指针: public: CRegisterDialog *m_pRegisterDlg; 注意将 CRegisterDialog 类的头文件包含在 CRegisterView 类的 定义文件中,或在定义对话框指针之前加入超前声明: class CRegisterDialog,在 CRegisterDialog 类中增加 CWnd 类型的指针数据成员,用 于保存其父窗口对象的指针(以便与父窗口进行联系), 并在构造函数中对该指针进行设置。 protected: CWnd* m_pParent; CRegisterDialog:CRegisterDialog(CWnd* pParent /*=

29、NULL*/) : CDialog(CRegisterDialog:IDD, pParent) /AFX_DATA_INIT m_pParent = pParent;,修改 CRegisterView 类构造函数和消息处理函数: CRegisterView:CRegisterView() / TODO: add construction code here m_pRegisterDlg = NULL; void CRegisterView:OnEditRegister() / TODO: Add your command handler code here if(m_pRegisterDlg)

30、/ 判断对话框已创建否? m_pRegisterDlg-SetActiveWindow(); / 激活已创建的对话框 else m_pRegisterDlg = new CRegisterDialog(this); / 创建对话框对象 m_pRegisterDlg-Create(IDD_REGISTER, this); / 创建窗口,使用 ClassWizard 为 CRegisterDialog 类添加 OnCancel、OnOK 消息响应函数和重载虚函数 PostNcDestroy,并为这两个函数 编写定义代码: void CRegisterDialog:OnCancel() / TODO

31、: Add extra cleanup here m_pParent-SendMessage(WM_DIALOG_DESTROY, 0, 0); /向父窗口发出关闭对话框消息 DestroyWindow();/ 关闭对话框窗口,void CRegisterDialog:OnOK() / TODO: Add extra validation here CString str; UpdateData(); m_pParent-GetWindowText(str); / 获取父窗口中的显示文本 / 在原来文本的基础上添加新文本 str += rn; str += 姓名:; str += m_strN

32、ame; 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 += 工作单位:; str += m_strUnit; str += rn; str += 单位性质:; str += m_str

33、Kind; 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();,对话框关闭时要求其父窗口类对象能及时将指向对话框的指 针设置为 NULL。实现方法

34、和步骤如下: 在 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; return 1;

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

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

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

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

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

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

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

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

43、的码段中加入相应的创建代码。例如: void CMyView:DoModalPropertySheet() CPropertySheet propsheet; / 创建属性表框架 CMyFirstPage pageFirst; / 创建第一属性页 CMySecondPage pageSecond; / 创建第二属性页 pageFirst.m_nMember1 = m_nMember1; / 初始化第一属性页 pageFirst.m_nMember2 = m_nMember2; / 初始化第一属性页 pageSecond.m_nMember3 = m_nMember3; / 初始化第二属性页 p

44、ageSecond.m_nmember4 = m_nMember4; / 初始化第二属性页,propsheet.AddPage(,使用 CPropertySheet 类的派生类创建 一般步骤如下: 使用 ClassWizard 定义一个 CPropertySheet 类的派生类; 将所有属性页类对象以数据成员的形式加入到此派生类的 定义中; 在此派生类构造函数中调用 CPropertySheet:AddPage 函数 将各个属性页添加到属性表中,使得在属性表对象的创建 操作自动包含了属性页的添加操作。 在需要使用属性表的地方,使用此派生的属性表类创建特 定的属性表,5.4.2 属性表的运行机制

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

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

47、页的这三个消息响应函数的调用并非直接 响应属性表的三个按钮的通知消息 BN_CLICKED 的结果,而 是通过 CPropertySheet 类或派生类对这三个按钮的消息响应函 数,间接调用上述 CPropertyPage 的三个消息响应函数完成的。 例如,定义响应 按钮的通知消息,完成特定的处理 可以有两种方法,使用 ClassWizard 为属性表中任意一个属性页类重定义虚 函数 OnApply,在该函数中定义要实现的特定功能代码。 一般情况下所定义的功能将对整个属性表起作用,所以 只须在一个属性页中重定义 OnApply 即可,不必为每个属 性页都重定义 OnApply。 在 CProp

48、ertySheet 的派生类中添加 按钮的通知消 息 BN_CLICKED 的消息映射和响应函数,在该函数中定义 想要实现的操作。注意,系统为 按钮定义的标识 为 ID_APLLY_NOW,但在VC 6.0 中 ClassWizard 无法识别该 标识 ,因此上述添加操作只能手工完成,4 CPropertyPage 类中几个与运行机制相关的重要成员函数: void SetModified( BOOL bChanged = TRUE ); 该函数用于设置属性页的修改标志。参数bChange 为 TRUE 表明属性页的属性已修改,否则表示未修改。调用该函数的 主要功能是“允许”或“禁止” 按钮:

49、只要在一个属性页中调用了 SetModified(),就会使 按钮的状态变为“允许”; 必须在所有的属性页中调用 SetModified(FALSE),才能使 按钮的状态变为“禁止,virtual BOOL OnSetActive( ); 当属性页被激活或被创建时,该函数将被程序框架调用。该 函数的缺省操作是: BEGIN if(属性页创建否?) then 激活已创建的属性页 else 创建属性页 endif 调用 UpdateData(FALSE) 刷新属性页内的控件。 END 可以重定义该虚函数完成一些所需要的工作,但执行这些特 定操作之前必须首先调用 CPropertyPage:OnSe

50、tActive,virtual BOOL OnKillActive( ); 当切换属性页时,被切换的属性页会调用该函数。该函数的 缺省操作是调用 UpdateData(TRUE) 保存数据。可以重定义该 虚函数完成一些特定数据的有效检查和操作。该函数的成功 返回将导致程序框架调用 OnOK 函数。 注意: 在属性表的一次调用中,表中的属性页并不一定都被创建 过。那些从未打开过的属性页就不会被创建。 只有确定属性页已经存在,才能调用与属性页和控件相关 的函数。如果收到了控件通知消息或 OnSetActive 函数被调 用,则表明属性页已经创建。 属性页之间的数据交换只能在 OnSetActive

51、 和 OnKillActive 函 数中进行,5.4.3 属性表的具体实例 创建一个属性表应用程序项目“Register3” ,在该项目中将 “Register” 应用程序对话框中的两组控件 “个人情况” 和 “单位情 况” 分解为属性表的两个属性页。创建属性表步骤如下: 1 创建第一个属性页 创建属性页资源 生成新对话框模板 IDD_PERSONAL; 去掉缺省的 和 按钮; 确定模板标题为 “个人信息” 作为该属性页的 “标签”; 设置模板属性:TitleBar、Child、ThinBoder 和 Disable; 添加所需要的控件:本例可以复制前例中对话框模板中的 相应的控件,定义属性页

52、类 CPersonalPage 使用 ClassWizard 为 IDD_PERSONAL 定义 CPropertyPage 派 生类 CPersonalPage。 使用 ClassWizard ,为各控件添加对应的数据对象,手工添加消息映射和处理函数: 在类定义文件中加入消息响应函数声明: afx_msg void OnChangeProperties(); /处理相应控件的 BN_CLICKED 消息 afx_msg void OnChangeProperties1(); /处理相应控件的 EN_CHANGE 消息 在类实现文件的消息映射表中加入: ON_CONTROL_RANGE( BN

53、_CLICKED,IDC_MARRIED, IDC_WORK1, OnChangeProperties ) ON_CONTROL_RANGE( EN_CHANGE, IDC_NAME, IDC_AGE, OnChangeProperties1,在类实现文件中加入消息响应函数的定义代码: void CPersonalPage:OnChangeProperties() SetModified(TRUE);/ 使能 Apply 按钮 UpdateData(TRUE);/ 确认数据设置 void CPersonalPage:OnChangeProperties1() SetModified(TRUE)

54、; / 使能 Apply 按钮 UpdateData(TRUE); / 确认数据设置,2 创建第二个属性页 创建属性页资源 生成新对话框模板 IDD_UNIT; 去掉缺省的 和 按钮; 确定模板标题为 “单位信息” 作为该属性页的 “标签”; 设置模板属性:TitleBar、Child、ThinBoder 和 Disable; 添加所需要的控件:本例可以复制前例中对话框模板中的 相应控件,定义属性页类 CUnitPage 使用 ClassWizard 为 IDD_UNIT 创建 CPropertyPage 的派生类 CUnitPage。 使用 ClassWizard 在类定义中,为各控件添加对

55、应的数据对 象,使用 ClassWizard 添加消息映射和处理函数: 在类定义文件中加入消息响应函数声明: afx_msg void OnChangeUnit(); afx_msg void OnSelchangeIncome(); afx_msg void OnEditchangeKind(); afx_msg void OnSelchangeKind(); 在类实现文件的消息映射表中加入: ON_EN_CHANGE(IDC_UNIT, OnChangeUnit) ON_LBN_SELCHANGE(IDC_INCOME, OnSelchangeIncome) ON_CBN_EDITCHAN

56、GE(IDC_KIND, OnEditchangeKind) ON_CBN_SELCHANGE(IDC_KIND, OnSelchangeKind,在类实现文件中加入处理函数的定义代码: void CUnitPage:OnChangeUnit() SetModified(TRUE); UpdateData(TRUE); void CUnitPage:OnSelchangeIncome() SetModified(TRUE); UpdateData(TRUE);,void CUnitPage:OnEditchangeKind() SetModified(TRUE); UpdateData(TRU

57、E); void CUnitPage:OnSelchangeKind() SetModified(TRUE); UpdateData(TRUE);,使用 ClassWizard 添加窗口消息 WM_INITDIALOG 的响应函数 OnInitDialog,并加入如下代码,为列表框进行初始化: BOOL CUnitPage:OnInitDialog() CPropertyPage:OnInitDialog(); / TODO: Add extra initialization here m_ctrlIncome.AddString(500元以下); m_ctrlIncome.AddString

58、(500-1000元); m_ctrlIncome.AddString(1000-2000元); m_ctrlIncome.AddString(2000元以上); return TRUE; / return TRUE unless you set the focus to a control / EXCEPTION: OCX Property Pages should return FALSE,重定义虚函数 OnSetActive 用于从 “个人情况” 属性页切换到 “单位情况” 属性页时的就业情况判断: BOOL CUnitPage:OnSetActive() / TODO: Add you

59、r specialized code here and/or call the base class BOOL result = CPropertyPage:OnSetActive(); if(result = 0) return result; if(CRegisterSheet*)GetParent()- m_PersonalPage.m_nWork=0) / 在职 GetDlgItem(IDC_UNIT)-EnableWindow(TRUE); GetDlgItem(IDC_KIND)-EnableWindow(TRUE); m_ctrlIncome.EnableWindow(TRUE)

60、; else,/ 下岗 GetDlgItem(IDC_UNIT)-SetWindowText(); GetDlgItem(IDC_UNIT)-EnableWindow(FALSE); m_strUnit = ; CComboBox *pComboBox = (CComboBox*)GetDlgItem(IDC_KIND); pComboBox-SetCurSel(-1); pComboBox-EnableWindow(FALSE); m_strKind = ; m_ctrlIncome.SetCurSel(-1); m_ctrlIncome.EnableWindow(FALSE); m_str

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论