1. CDialog类的基本使用方法:
1) 在创建自己的对话框之前必须先从CDialog类派生出自己的类,并在派生类中定义一些自己的数据域以及其它新的函数;
2) CDialog中继承来的最重要的三个函数都是消息响应函数:OnInitDialog、OnOK、OnCancel函数
i. OnInitDialog相应的WM_INITDIALOG消息,该函数主要负责初始化对话框中的控件;
ii. 所有的对话框基本应该含有OK按钮和Cancel按钮来结束对话框,因此模板对话框中也默认包含这两个按钮,并提供后面两个函数来相应对这两个按钮的点击;
iii. 这三个函数的消息映射、消息映射的定义都不需要写,因为MFC底层都已经帮你定义好了(都在CDialog内部定义过了);
!!要是OnOK和OnCancel函数自动起作用(不自己定义消息映射等)必须将两个按钮的ID定义为IDOK和IDCANCEL(如果自己修改代码的话),这两个宏也是在MFC底层定义过的;
!!这三个函数在.h文件中就直接以virtual虚函数的形式给出原型了,并没有消息映射的宏定义(MFC底层定义好了);
2. 对话框创建的消息处理顺序:
1) 首先对话框会相应WM_CREATE消息在内存中创建整个对话框的框架资源,但此时其中的控件并没有创建,此时对话框是空的;
2) 接着MFC的内部的某个过程函数也相应WM_CREATE消息并逐个创建对话框中的控件于内存中;
3) 控件也创建好后就会收到WM_INITDIALOG消息,这是可以在OnInitDialog函数中初始化控件,比如给复选框打钩、决定初始的单选项、给编辑框定义初始文本等,但是OnInitDialog并不创建控件,创建控件是上一步过程函数的事;
4) 最后便显示整个对话框和其中的控件了;
3. 关于OnInitDialog函数的返回值和初始焦点的问题:
1) 可以通过OnInitDialog的返回值来决定如何设置对话框初始时的焦点落在哪个控件上;
2) 如果返回值为TRUE,则Windows直接将初始焦点放在Tab顺序的第一个控件上;
3) 如果你想特别指定初始焦点,则必须返回一个FALSE来告诉Windows,初始焦点不用你来替我设置了,具体怎么设置请到我的OnInitDialog函数的代码中找吧;
4) 如果返回FALSE则具体的设置初始焦点的方法就是调用控件的SetFocus函数(继承自CWnd,控件是一种特殊的窗口):
i. 函数原型:CWnd* CWnd::SetFocus();
ii. 返回的是之前具有焦点的窗口的指针;
!!那么最大问题就是如何在OnInitDialog中获取控件的指针呢?只有获取控件指针之后才能调用其成员函数:
a. 使用对话框的成员函数GetDialogItem就可以轻松获取其中的控件的指针了;
b. 该函数直接继承自CWnd,其原型为:CWnd* CWnd::GetDlgItem(int nID) const;
c. nID就是目标控件的ID,返回值就是目标控件的指针,但不过是CWnd*类型的,如果想使用控件类特有的成员必须先进行类型转换才行!!千万别忘了!否则会发生类型错误!!
iii. 设置初始焦点只要GetDlgItem(nID)->SetFocus()即可,然后返回值必须是FALSE;
4. 关于覆盖OnOK和OnCancel函数的注意事项:
1) 这两个函数最大的特点就是执行完之后会关闭对话框(按完确定或取消按钮之后必定会关闭对话框);
2) 所以如果自己要覆盖这两个函数的话一定要在最后调用基类的OnOK和OnCancel函数来完成关闭对话框的功能;
3) 而实际上基类的函数是调用了EndDialog函数来关闭对话框,该函数会在后面详细讲解;
5. 利用CDialog派生类的对象创建模态对话框:
1) 首先利用构造函数创建对象,创建的同时并绑定脚本编译得到的对话框资源;
2) CDialog的构造函数中包含一个参数,该参数就是指定脚本资源中对话框的资源ID:
i. 函数原型:有两个版本,一个绑定字符串型的模板ID,另一个绑定整型的模板ID
CDialog::CDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL);
CDialog::CDialog(UINT nIDTemplate, CWnd* pParentWnd);
ii. pParenWnd是对话框所有者的指针,如果该所有者是应用程序的主窗口则直接传NULL即可;
iii. 综上,一般会自定义一个派生类的构造函数来将上述功能包装起来,例如:
CMyDialog::CMyDialog(CWnd* pParentWnd = NULL) :
CDialog(IDD_MYDIALOG, pParentWnd) {}
!这样的话就会在创建对象时更加方便,而且非常安全,可以避免将错误的资源ID传给构造函数;
3) 接下来就是使用CDialog的DoModal函数来创建并显示对话框了:
i. 函数原型:virtual int CDialog::DoModal();
ii. 返回值即为用户退出对话框时选中的那个按钮的ID,如果选的是OK按钮则返回IDOK,或者是IDCANCEL;
iii. 程序可以根据DoModal的返回值来进行不同的逻辑处理,例如:if (dlg.DoModal() == IDOK) { ... } else { ... }
4) 创建用户自定的对话框退出按钮:用户当然可以在OK和Cancel之外定义其它按钮,按下后,处理一定任务的同时并退出,此时当然得要求DoModal返回的是该自定义按钮的ID了
i. 由于OK和Cancel都是MFC预先实现的,因此像这样的自定义的退出按钮就需要通过一定手段达到和OK、Cancel差不多的效果,这个效果就是关闭对话框的效果;
ii. 这里就要用到我们前面所说的EndDialog函数了,DoModal的返回值即为传给EndDialog的参数,也就是说EndDialog的参数直接指定了DoModal的返回值;
iii. EndDialog的原型:void CDialog::EndDialog(int nResult); // 在关闭对话框的同时也指定了DoModal的返回值;
iv. 因此要添加自定义的退出按钮可以这样写:对话框中控件的消息映射和普通窗口一模一样
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
ON_BN_CLICKED(IDC_RESET, OnResetDialog)
END_MESSAGE_MAP()
void CMyDialog::OnResetDialog() {
EndDialog(IDC_RESET);
}
...
CMyDialog dlg;
int nRet = dlg.DoModal();
if (nRet == IDOK) ...
else if (nRet == IDC_RESET) ...
!!用户自定义退出按钮的ID一定要大于等于3,因为IDOK和IDCANCEL分别是1和2,这两个是MFC预定义的;