WEB开发网
开发学院软件开发VC MFC教程(12)-- 对话框和对话框类CDialog(1)... 阅读

MFC教程(12)-- 对话框和对话框类CDialog(1)

 2010-03-25 20:35:00 来源:WEB开发网   
核心提示:消息预处理和Dialog消息另外,对话框窗口的消息处理还有一个特点,MFC教程(12)-- 对话框和对话框类CDialog(1)(7),就是增加了对Dialog消息的处理,如同在介绍::IsDialogMessage函数时所述,RunModalLoop是给父窗口发送WM_ENTERIDLE消息(如果需要的话);另外,当

消息预处理和Dialog消息

另外,对话框窗口的消息处理还有一个特点,就是增加了对Dialog消息的处理,如同在介绍::IsDialogMessage函数时所述。如果是Dialog消息,MFC框架将不会让它进入下一步的消息循环。为此,MFC覆盖了CDialog的虚拟函数PreTranslateMessage,该函数的实现如下:

BOOL CDialog::PreTranslateMessage(MSG* pMsg)
{
// 用于无模式或者模式对话框的处理
ASSERT(m_hWnd != NULL);
//过滤tooltip messages
if (CWnd::PreTranslateMessage(pMsg))
return TRUE;
//在Shift+F1帮助模式下,不转换Dialog messages
CFrameWnd* pFrameWnd = GetTopLevelFrame();
if (pFrameWnd != NULL && pFrameWnd->m_bHelpMode)
return FALSE;
//处理Escape键按下的消息
if (pMsg->message == WM_KEYDOWN &&
(pMsg->wParam == VK_ESCAPE || pMsg->wParam == VK_CANCEL) &&
(::GetWindowLong(pMsg->hwnd, GWL_STYLE) & ES_MULTILINE) &&
_AfxCompareClassName(pMsg->hwnd, _T("Edit")))
{
HWND hItem = ::GetDlgItem(m_hWnd, IDCANCEL);
if (hItem == NULL || ::IsWindowEnabled(hItem))
{
SendMessage(WM_COMMAND, IDCANCEL, 0);
return TRUE;
}
}
// 过滤来自控制该对话框子窗口的送给该对话框的Dialog消息
return PreTranslateInput(pMsg);
}

从其实现可以看出,如果是Tooltip消息或者Dialog消息,这些消息将在PreTranslateMessage中被处理,不会进入消息发送的处理。

PreTranslateInput是CWnd的成员函数,它调用::IsDialogMessage函数来处理Dialog消息。

PreTranslateMessage的实现不仅用于模式对话框,而且用于无模式对话框。

模式对话框的消息循环

从DoModal的实现可以看出,DoModal调用CreateDlgIndirect创建的是无模式对话框,MFC如何来接管和控制应用程序的消息队列,实现一个模式对话框的功能呢?

CDialog调用了RunModalLoop来实现模式窗口的消息循环。RunModalLoop是CWnd的成员函数,它和相关函数的实现如下:

int CWnd::RunModalLoop(DWORD dwFlags)
{
ASSERT(::IsWindow(m_hWnd)); //窗口必须已经创建且不在模式状态 ASSERT(!(m_nFlags & WF_MODALLOOP));
// 以下变量用于Idle处理
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
BOOL bShowIdle = (dwFlags & MLF_SHOWONIDLE) &&
!(GetStyle() & WS_VISIBLE);
HWND hWndParent = ::GetParent(m_hWnd);
m_nFlags |= (WF_MODALLOOP|WF_CONTINUEMODAL);
MSG* pMsg = &AfxGetThread()->m_msgCur;
//获取和派发消息直到模式状态结束
for (;;)
{
ASSERT(ContinueModal());
//第一阶段,判断是否可以进行Idle处理
while (bIdle &&!::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE))
{
ASSERT(ContinueModal());
//必要的话,当Idle时显示对话框窗口
if (bShowIdle)
{
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
bShowIdle = FALSE;
}
// 进行Idle处理
//必要的话发送WM_ENTERIDLE消息给父窗口
if (!(dwFlags & MLF_NOIDLEMSG) &&hWndParent != NULL && lIdleCount == 0)
{
::SendMessage(hWndParent, WM_ENTERIDLE,
MSGF_DIALOGBOX, (LPARAM)m_hWnd);
}
//必要的话发送WM_KICKIDLE消息给父窗口
if ((dwFlags & MLF_NOKICKIDLE) ||
!SendMessage(WM_KICKIDLE, MSGF_DIALOGBOX, lIdleCount++))
{
//终止Idle处理
bIdle = FALSE;
}
}
//第二阶段,发送消息
do
{
ASSERT(ContinueModal());
// 若是WM_QUIT消息,则发送该消息到消息队列,返回;否则发送消息。
if (!AfxGetThread()->PumpMessage())
{
AfxPostQuitMessage(0);
return -1;
}
//必要的话,显示对话框窗口
if (bShowIdle &&
(pMsg->message == 0x118 || pMsg->message == WM_SYSKEYDOWN))
{
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
bShowIdle = FALSE;
}
if (!ContinueModal())
goto ExitModal;
//在派发了“正常 ”消息后,重新开始Idle处理
if (AfxGetThread()->IsIdleMessage(pMsg))
{
bIdle = TRUE;
lIdleCount = 0;
}
} while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE));
}
ExitModal:
m_nFlags &= ~(WF_MODALLOOP|WF_CONTINUEMODAL);
return m_nModalResult;
}
BOOL CWnd::ContinueModal()
{
return m_nFlags & WF_CONTINUEMODAL;
}
void CWnd::EndModalLoop(int nResult)
{
ASSERT(::IsWindow(m_hWnd));
// this result will be returned from CWnd::RunModalLoop
m_nModalResult = nResult;
// make sure a message goes through to exit the modal loop
if (m_nFlags & WF_CONTINUEMODAL)
{
m_nFlags &= ~WF_CONTINUEMODAL;
PostMessage(WM_NULL);
}
}

和CWinThread::Run的处理过程比较,RunModalLoop也分两个阶段进行处理。不同之处在于,这里不同于Run的Idle处理,RunModalLoop是给父窗口发送WM_ENTERIDLE消息(如果需要的话);另外,当前对话框的父窗口被Disabled,是不接收用户消息的。

上一页  2 3 4 5 6 7 

Tags:MFC 教程 对话框

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接