本学习笔记主要参考了鸡啄米的mfc编程入门
MFC四个主要类的关系:
假设创建了HelloWorld的工程,CHelloWorldApp类处理消息,讲收到的消息分发给相应的对象。CMainFrame是视图CHelloWorldView的父窗口,视图CHelloWorldView就显示在CMainFrame的客户区中。视图类CHelloWorldView用来显示文档类CHelloWorldDoc中的数据,并根据对视图类的操作修改文档类的数据。一个视图类只能跟一个文档类相联系,而一个文档类可以跟多个视图类相联系。
MFC消息映射机制
MFC使用一种消息映射机制来处理消息,在应用程序框架中的表现就是一个消息与消息处理函数一一对应的消息映射表,以及消息处理函数的声明和实现等代码。当窗口接收到消息时,会到消息映射表中查找该消息对应的处理函数,然后由消息处理函数进行相应的处理。SDK编程时需要在窗口过程中一一判断消息值进行相应的处理,相比之下MFC的消息映射机制要方便好用。
Windows消息分类:
- 标准Windows消息。除WM_COMMAND外以WM_开头的消息是标准消息。例如,WM_CREATE、WM_CLOSE。
- 命令消息。消息名为WM_COMMAND,消息中附带了标识符ID来区分是来自哪个菜单、工具栏按钮或者加速键的消息。
- 通知消息。通知消息一般由列表框等子窗口发送给父窗口,消息名也为WM_COMMAND,其中附带了控件通知码来区分控件。
CWnd的派生类都可以接收到标准Windows消息、通知消息、命令消息。命令消息还可以由文档类等接收。
消息映射:
在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP()之间的内容就是 消息映射入口项。消息映射除了在CMainFrame的实现文件中添加消息映射表之外,在类的定义文件MainFrame.h中还会添加一个宏调用:DECLARE_MESSAGE_MAP。
添加消息处理函数的三个步骤:
- 在类定义中加入消息处理函数的函数声明,注意要以afx_msg开头。
- 在类的消息映射表中添加该消息的消息映射入口项。例如WM_CREATE的消息映射入口项:ON_WM_CREATE()。
- 在类的实现中添加消息处理函数的函数实现。
创建对话框模板和修改对话框属性
创建对话框的步骤:
- 创建对话框资源,主要包括创建新的对话框模板、设置对话框属性和为对话框添加各种控件;
- 生成对话框类,主要包括新建对话框类、添加控件变量和控件的消息处理函数等。
创建对话框类和添加控件变量
创建好对话框资源后要做的就是生成对话框类,主要包括新建对话框类、添加控件变量和控件的消息处理函数等。一般类名以C开头,变量名以m开头。static text和button不需要添加变量,edit control中的数据可能经常变化,有必要为它们每个控件关联一个变量。添加完成后会在类里面多出DDX_Text的调用语句,主要用于数据交换。
数据交换机制中,DoDataExchang()并不是自动调用的,而是需要我们在程序中调用CDialogEx::UpdateData()函数,由UpdateData()函数再去调用DoDataExchang()。
CDialogEx::UpdateData()函数的原型为 :
BOOL UpdateData(BOOL bSaveAndValidate = TRUE);
参数:bSaveAndValidate用于指示数据传输的方向,TRUE表示从控件传给变量,FALSE表示从变量传给数据。默认值是TRUE,即从控件传给变量。
返回值:CDialogEx::UpdateData()函数的返回值表示操作是否成功,成功则返回TRUE,否则返回FALSE。
返回值:CDialogEx::UpdateData()函数的返回值表示操作是否成功,成功则返回TRUE,否则返回FALSE。
为控件添加消息处理函数
MFC为对话框和控件等定义了诸多消息,我们对它们操作时会触发消息,这些消息最终由消息处理函数处理。比如我们点击按钮时就会产生BN_CLICKED消息,修改编辑框内容时会产生EN_CHANGE消息等。一般为了让某种操作打到效果,我们只需要实现某个消息的消息处理函数。
添加消息处理函数
- 使用Class Wizard添加消息处理函数。在Commands标签下,Object IDs列表中找到需要的ID,在Message列表中选择BN_CLICKED消息,然后点Add Handler就可以添加BN_CLICKED的消息处理函数OnClickedAddButton。
- 通过Add Event Handler添加消息处理函数。
- 在按钮的属性视图中添加消息处理函数。
- 双击按钮添加消息处理函数。
- 添加消息处理函数
在消息处理函数中添加自定义功能
函数体中添加UpdateData(TRUE);和UpdateData(FALSE);
点按钮后进入函数体,首先由UpdateData(TRUE)函数将变量值保存到变量中,执行自定义语句后,调用UpdateData(FALSE)函数更新编辑框的显示值。
设置对话框控件的Tab顺序
在资源管理器中找到对话框,打开模板视图模板,Ctrl+D就可以显示各个控件的Tab顺序数字,单击控件就可以改变Tab顺序。
模态对话框及其弹出过程
Windows对话框分为两类:模态对话框和非模态对话框。模态对话框是当它弹出后,本应用程序其他窗口将不再接受用户输入,只有该对话框响应用户输入,在对他进行相应的操作退出后,其他窗口才能继续与用户交互;非模态对话框是弹出后,本程序其他窗口仍能响应用户输入。一般用来显示提示信息。
关键性函数是对话框类的DoModal()函数。CDialog::DoModal()函数的原型为:
virtual INT_PTR DoModal();
返回值:整数值,指定了传递给CDialog::EndDialog(该函数用于关闭对话框)的nResult参数值。如果函数不能创建对话框,则返回-1;如果出现其它错误,则返回IDABORT。
调用了它对话框就会弹出,返回值是退出对话框时所点的按钮的ID,比如,我们点了“退出”按钮,那么DoModal返回值为IDCANCEL。参考鸡啄米的计算器代码来说明
void CAdditionDlg::OnBnClickedAddButton()
{
// TODO: Add your control notification handler code here
INT_PTR nRes; // 用于保存DoModal函数的返回值
CTipDlg tipDlg; // 构造对话框类CTipDlg的实例
nRes = tipDlg.DoModal(); // 弹出对话框
if (IDCANCEL == nRes) // 判断对话框退出后返回值是否为IDCANCEL,如果是则return,否则继续向下执行
return;
// 将各控件中的数据保存到相应的变量
UpdateData(TRUE);
// 将被加数和加数的加和赋值给m_editSum
m_editSum = m_editSummand + m_editAddend;
// 根据各变量的值更新相应的控件。和的编辑框会显示m_editSum的值
UpdateData(FALSE);
}
非模态对话框的创建及显示
需要修改的是,对话框类实例的创建和显示,也就是之前在CAdditionDlg::OnBnClickedAddButton()函数体中添加的对话框显示代码。下面是具体步骤:
- 在AdditionDlg.h中包含CTipDlg头文件并定义CTipDlg类型的指针成员变量。详细操作方法是,在AdditionDlg.cpp中删除之前添加的#include "TipDlg.h",而在AdditionDlg.h中添加#include "TipDlg.h",这是因为我们需要在AdditionDlg.h中定义CTipDlg类型的指针变量,所以要先包含它的头文件;然后在AdditionDlg.h中为CAdditionDlg类添加private成员变量CTipDlg *m_pTipDlg;。
- 在CAdditionDlg类的构造函数中初始化成员变量m_pTipDlg。如果cpp文件中函数太多,我们可以在Class View上半个视图中找到CAdditionDlg类,再在下半个视图中找到其构造函数双击,中间客户区域即可马上切到构造函数的实现处。在构造函数体中添加m_pTipDlg = NULL;,这是个好习惯,鸡啄米在C++编程入门系列的指针的赋值和指针运算中说到过,在任何指针变量使用前都初始化,可以避免因误访问重要内存地址而破坏此地址的数据。
void CAdditionDlg::OnBnClickedAddButton()
{
// TODO: Add your control notification handler code here
/*INT_PTR nRes; // 用于保存DoModal函数的返回值
CTipDlg tipDlg; // 构造对话框类CTipDlg的实例
nRes = tipDlg.DoModal(); // 弹出对话框
if (IDCANCEL == nRes) // 判断对话框退出后返回值是否为IDCANCEL,如果是则return,否则继续向下执行
return;*/
// 如果指针变量m_pTipDlg的值为NULL,则对话框还未创建,需要动态创建
if (NULL == m_pTipDlg)
{
// 创建非模态对话框实例
m_pTipDlg = new CTipDlg();
m_pTipDlg->Create(IDD_TIP_DIALOG, this);
}
// 显示非模态对话框
m_pTipDlg->ShowWindow(SW_SHOW);
// 将各控件中的数据保存到相应的变量
UpdateData(TRUE);
// 将被加数和加数的加和赋值给m_editSum
m_editSum = m_editSummand + m_editAddend;
// 根据各变量的值更新相应的控件。和的编辑框会显示m_editSum的值
UpdateData(FALSE);
} 因为此非模态对话框实例是动态创建的,所以需要手动删除此动态对象来销毁对话框。我们在CAdditionDlg类的析构函数中添加删除代码,但是MFC并没有自动给出析构函数,这时需要我们手动添加,在对话框对象析构时就会调用我们自定义的析构函数了。在AdditionDlg.h文件中为CAdditionDlg添加析构函数声明:~CAdditionDlg();,然后在AdditionDlg.cpp文件中添加析构函数的实现,函数体如下:CAdditionDlg::~CAdditionDlg()
{
// 如果非模态对话框已经创建则删除它
if (NULL != m_pTipDlg)
{
// 删除非模态对话框对象
delete m_pTipDlg;
}
}属性页对话框及相关类的介绍
属性页对话框就是包含一般属性页对话框和向导对话框两类。它将多个对话框集成与一身,通过标签或按钮来切换页面。主要有两个类:CPropertyPage类和CPropertySheet类
- CPropertyPage类
(1)构造函数
这里讲三个CProperty类的构造函数,函数原型为:
CPropertyPage( );
explicit CPropertyPage(
UINT nIDTemplate,
UINT nIDCaption = 0,
DWORD dwSize = sizeof(PROPSHEETPAGE)
);
explicit CPropertyPage(
LPCTSTR lpszTemplateName,
UINT nIDCaption = 0,
DWORD dwSize = sizeof(PROPSHEETPAGE)
);
第一个是没有任何参数的构造函数。
第二个构造函数中,参数nIDTemplate是属性页的对话框资源ID,参数nIDCaption是属性页对话框选项卡的标题所用字符串资源的ID,若设为0,则选项卡标题就使用该属性页的对话框资源的标题。
第三个构造函数中,参数lpszTemplateName为属性页的对话框资源的名称字符串,不能为NULL。参数nIDCaption同上。
(2)CancelToClose()函数
在模态属性页对话框的属性页进行了某不可恢复的操作后,使用CancelToClose()函数将“OK”按钮改为“Close”按钮,并禁用“Cancel”按钮。函数原型为:
void CancelToClose( );
(3)SetModified()函数
调用此函数可激活或禁用“Apply”按钮,函数原型为:
void SetModified(BOOL bChanged = TRUE);
(4)可重载函数
CPropertyPage类提供了一些消息处理函数,来响应属性页对话框的各种消息。我们重载这些消息处理函数,就可以自定义对属性页对话框操作的处理。可重载的消息处理函数包括:
OnApply:处理属性页的“Apply”按钮被单击的消息
OnCancel:处理属性页的“Cancel”按钮被单击的消息
OnKillActive:处理属性页当前活动状态被切换的消息,常用于数据验证
OnOK:处理属性页的“OK”按钮、“Apply”按钮或者“Close”按钮被单击的消息
OnQueryCancel:处理属性页的“Cancel”按钮被单击前发出的消息
OnReset:处理属性页的“Reset”按钮被单击的消息
OnSetActive:处理属性页被切换为当前活动页的消息
OnWizardBack:处理属性页的“Next”按钮被单击的消息,仅在向导对话框中有效
OnWizardFinish:处理属性页的“Finish”按钮被单击的消息,仅在向导对话框中有效
OnWizardNext:处理属性页的“下一步”按钮被单击的消息,仅在向导对话框中有效
- CPropertySheet类
CPropertySheet类继承自CWnd类,它是属性表类,负责加载、打开或删除属性页,并可以在属性页对话框中切换属性页。它跟对话框类似,也有模态和非模态两种。
(1)构造函数
这里依然列出CPropertySheet类的三个构造函数:
CPropertySheet( );
explicit CPropertySheet(
UINT nIDCaption,
CWnd* pParentWnd = NULL,
UINT iSelectPage = 0
);
explicit CPropertySheet(
LPCTSTR pszCaption,
CWnd* pParentWnd = NULL,
UINT iSelectPage = 0
);
参数nIDCaption:标题的字符串资源的ID。
参数pParentWnd:属性页对话框的父窗口,若设为NULL,则父窗口为应用程序的主窗口。
参数iSelectPage:初始状态时,活动属性页的索引,默认为第一个添加到属性表的属性页。
参数pszCaption:标题字符串。
(1)构造函数
这里依然列出CPropertySheet类的三个构造函数:
CPropertySheet( );
explicit CPropertySheet(
UINT nIDCaption,
CWnd* pParentWnd = NULL,
UINT iSelectPage = 0
);
explicit CPropertySheet(
LPCTSTR pszCaption,
CWnd* pParentWnd = NULL,
UINT iSelectPage = 0
);
参数nIDCaption:标题的字符串资源的ID。
参数pParentWnd:属性页对话框的父窗口,若设为NULL,则父窗口为应用程序的主窗口。
参数iSelectPage:初始状态时,活动属性页的索引,默认为第一个添加到属性表的属性页。
参数pszCaption:标题字符串。
(2)GetActiveIndex()函数
获取当前活动属性页的索引。函数原型为:
int GetActiveIndex( ) const;
返回值:当前活动属性页的索引。
(3)GetActivePage()函数
获取当前活动属性页对象。函数原型为:
CPropertyPage* GetActivePage( ) const;
返回值:当前活动属性页对象的指针。
(4)GetPage()函数
获取某个属性页对象。函数原型为:
CPropertyPage* GetPage(int nPage) const;
参数nPage:目标属性页的索引。
返回值:目标属性页对象的指针。
(5)GetPageCount()函数
获取属性页的数量。函数原型为:
int GetPageCount( ) const;
返回值:属性页的数量。
(6)GetPageIndex()函数
获取某属性页在属性页对话框中的索引。函数原型为:
int GetPageIndex(CPropertyPage* pPage);
参数pPage:要获取索引的属性页对象的指针。
返回值:属性页对象在属性页对话框中的索引。
(7)SetActivePage()函数
设置某个属性页为活动属性页。函数原型为:
BOOL SetActivePage(
int nPage
);
BOOL SetActivePage(
CPropertyPage* pPage
);
参数nPage:要设置为活动属性页的索引。
参数pPage:要设置为活动属性页的对象指针。
(8)SetWizardButtons()函数
45
在向导对话框上启用或禁用Back、Next或Finish按钮,应在调用DoModal之前调用此函数。函数原型为:
void SetWizardButtons(
DWORD dwFlags
);
参数dwFlags:设置向导按钮的外观和功能属性。可以是以下值的组合:
PSWIZB_BACK 启用“Back”按钮,如果不包含此值则禁用“Back”按钮。
PSWIZB_NEXT 启用“Next”按钮,如果不包含此值则禁用“Next”按钮。
PSWIZB_FINISH 启用“Finish”按钮。
PSWIZB_DISABLEDFINISH 显示禁用的“Finish”按钮。
(9)SetWizardMode()函数
设置属性页对话框为向导对话框模式,应在调用DoModal之前调用此函数。函数原型为:
void SetWizardMode( );
(10)SetTitle()函数
设置属性对话框的标题。函数原型为:
void SetTitle(
LPCTSTR lpszText,
UINT nStyle = 0
);
参数lpszText:标题字符串。
参数nStyle:指定属性表标题的风格。应当为0或PSH_PROPTITLE。如果设为PSH_PROPTITLE,则单词“Properties”会出现在指定标题之后。例如,SetTitle("Simple",PSH_PROPTITLE)这种调用会使得属性表标题为“Simple Properties”。
(11)AddPage()函数
为属性对话框添加新的属性页。函数原型为:
void AddPage(CPropertyPage *pPage);
参数pPage:要添加的新的属性页的对象指针。
(12)PressButton()函数
模拟按下某指定的按钮。函数原型为:
void PressButton(int nButton);
参数nButton:要模拟按下的按钮,它可以是下列值之一:
PSBTN_BACK 选择“Back”按钮。
PSBTN_NEXT 选择“Next”按钮。
PSBTN_FINISH 选择“Finish”按钮。
PSBTN_OK 选择“OK”按钮。
PSBTN_APPLYNOW 选择“Apply”按钮。
PSBTN_CANCEL 选择“Cancel”按钮。
PSBTN_HELP 选择“帮助”按钮。
(13)RemovePage()函数
删除某属性页。函数原型为:
void RemovePage(CPropertyPage *pPage);
void RemovePage(int nPage);
参数pPage:要删除的属性页的对象指针。
参数nPage:要删除的属性页的索引。

9829

被折叠的 条评论
为什么被折叠?



