12.对话框和对话框类CDialog(3)

2019-02-15 22:03

// hide the window before enabling the parent, etc.

if (m_hWnd != NULL)

SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW| SWP_NOSIZE|SWP_NOMOVE| SWP_NOACTIVATE|SWP_NOZORDER); } }

CATCH_ALL(e) {

DELETE_EXCEPTION(e); m_nModalResult = -1; }

END_CATCH_ALL

//Enable并且激活父窗口 if (bEnableParent)

::EnableWindow(hWndParent, TRUE);

if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)

::SetActiveWindow(hWndParent);

//::EndDialog仅仅关闭了窗口,现在销毁窗口 DestroyWindow(); PostModal();

// 必要的话,解锁/释放资源

if (m_lpszTemplateName != NULL || m_hDialogTemplate != NULL) UnlockResource(hDialogTemplate); if (m_lpszTemplateName != NULL) FreeResource(hDialogTemplate); return m_nModalResult; }

从DoModal的实现可以看出:

它首先Disable对话框窗口的父窗口;然后使

用::CreateIndrectDialog创建对话框窗口,使用子类化的方法用AfxWndProc(或者AfxBaseProc)替换了原来的窗口过程,并把原来的窗口过程保存在CWnd的成员变量m_pfnSuper中。原来的窗口过程就是::DialogBox等创建对话框窗口时指定的,是Windows内部提供的对话框“窗口类”的窗口过程。取代(Subclass)原来“窗口类”的窗口过程的方法如同 4.4.1节描述的CWnd::Create。

在::CreateIndirectDialog创建对话框窗口后,会发送WM_INITDIALOG消息给对话框的对话框过程(必要的话,还有WM_SETFONT消息)。但是MFC取代了原来的对话框窗口过程,这两个消息如何送给对话框过程呢?处理方法如下节所描述。 3. 使用原对话框窗口过程作消息的缺省处理

对话框的消息处理过程和其他窗口并没有什么不同。这里主要分析的是如何把一些消息传递给对话框原窗口过程处理。下面,通过解释MFC对WM_INITDIALOG消息的处理来解释MFC窗口过程和原对话框窗口过程的关系及其协调作用。

MFC提供了WM_INITDIALOG消息的处理函数

CDialog::HandleInitDialog,WM_INITDIALOG消息按照标准Windows的处理送给HandleInitDialog处理。

HandleInitDialog调用缺省处理过程Default,导致CWnd的Default函数被调用。CWnd::Default的实现如下:

LRESULT CWnd::Default() {

// call DefWindowProc with the last message _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();

return

DefWindowProc(pThreadState->m_lastSentMsg.message,

pThreadState->m_lastSentMsg.wParam, pThreadState->m_lastSentMsg.lParam); }

顺便指出,从Default的实现可以看出线程状态的一个用途:它把本线程最新收到和处理的消息记录在成员变量m_lastSentMsg中。

在Default的实现中,CWnd的DefWindowsProc被调用,其实现如下:

LRESULT CWnd::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam) {

//若“窗口超类(SuperClass)”的窗口过程m_pfnSuper非空,则调用它 if (m_pfnSuper != NULL)

return ::CallWindowProc(m_pfnSuper, m_hWnd, nMsg, wParam, lParam);

//在MFC中,GetSuperWndProcAddr的作用就是返回m_pfnSuper,为什么还

//要再次调用呢?因为虽然该函数现在是Obsolete,但原来曾经是有用的。如

//果返回非空,就调用该窗口过程进行处理,否则,由Windows进行缺省处理。 WNDPROC pfnWndProc;

if ((pfnWndProc = *GetSuperWndProcAddr()) == NULL)

return ::DefWindowProc(m_hWnd, nMsg, wParam, lParam); else

return ::CallWindowProc(pfnWndProc, m_hWnd, nMsg, wParam, lParam); }

综合上述分析,HandleInitDialog最终调用了窗口过程m_pfnSuper,即Windows提供给“对话框窗口类”的窗口过程,于是该窗口过程调用了对话框过程AfxDlgProc,导致虚拟函数OnInitDialog被调用。 顺便提一下,CWnd::AfxCallWndProc在处理

WM_INITDIALOG消息之前和之后都会有一些特别的处理,如尝试把对话框放到屏幕中间。具体实现这里略。

OnInitDialog的MFC缺省实现主要完成三件事情: 调用ExecInitDialog初始化对话框中的控制;调用UpdateData初始化对话框控制中的数据;确定是否显示帮助按钮。所以,程序员覆盖该函数时,一定要调用基类的实现。

MFC采用子类化的方法取代了对话框的窗口过程,实现了12.1节描述的模式对话框窗口的一些特性,原来SDK下对话框过程要处理的东西大部分转移给MFC窗口过程处理,如处理控制窗口的控制通知消息等。如果不能处理或者必须借助于原来的窗口过程的,则通过缺省处理函数Default传递给原来的窗口过程处理,如同这里对WM_INITDIALOG的处理一样。

4. Dialog命令消息和控制通知消息的处理

通过覆盖CWnd的命令消息发送函数OnCmdMsg,CDialog实现了自己的命令消息发送路径。在

4.4.3.3节,曾经分析了CDialog::OnCmdMsg函数,这里给出其具体实现:

BOOL CDialog::OnCmdMsg(UINT nID, int nCode, void* pExtra,

AFX_CMDHANDLERINFO* pHandlerInfo) {

//首先,让对话框窗口自己或者基类处理 if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE;

//如果还未处理,且是控制通知消息或者状态更新消息或者系统命令 //则停止进一步的发送

if ((nCode != CN_COMMAND && nCode != CN_UPDATE_COMMAND_UI) ||

!IS_COMMAND_ID(nID) || nID >= 0xf000) {

return FALSE; // not routed any further }

//尝试给父窗口处理

CWnd* pOwner = GetParent(); if (pOwner != NULL) {

#ifdef _DEBUG


12.对话框和对话框类CDialog(3).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:开放性试题测试

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: