如何创建一个模态对话框
我们创建的窗口类从CBkDialogImpl继承而来,这个窗口就是一个模态的窗口,我们需要调用其DoModal方法,但是在界面库里面是如何实现的一个模态的对话框呢。
核心就在这个类中的_ModalMessageLoop方法,我们来研究一下。
void _ModalMessageLoop()
{
BOOL bRet;
MSG msg;
for(;;)
{
if(::PeekMessage(&msg,NULL, 0, 0, PM_NOREMOVE))
{
if(WM_QUIT == msg.message)
break;
}
if(m_bExitModalLoop || NULL == m_hWnd || !::IsWindow(m_hWnd))
break;
bRet= ::GetMessage(&msg,NULL, 0, 0);
if(bRet == -1)
{
continue; // error, don'tprocess
}
elseif (!bRet)
{
ATLTRACE(L"Why ReceiveWM_QUIT here?\r\n");
break; // WM_QUIT, exitmessage loop
}
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
在这个函数里面建立了一个消息处理循环。
首先进行WM_QUIT消息的检测,并且采用PM_NOREMOVE的方式,如果获得了这个消息,那么退出消息循环,在之后的DoModal函数中模态窗口就被销毁了。
然后检测bExitModalLoop标志,如果这个标志位为TRUE的话那么也退出处理。我们来看一下退出模态的函数:
void EndDialog(UINT uRetCode)
{
m_uRetCode = uRetCode;
m_bExitModalLoop = TRUE;
// DestroyWindow里面直接Send了WM_DESTROY,所以不会跑到DoModal的消息循环里,所以有了下面那行代码
// DestroyWindow();
// 这句非常重要,可以让DoModal消息循环再跑一次,防止卡死在GetMessage,泪奔
::PostThreadMessage(::GetCurrentThreadId(), WM_NULL,0, 0);
}
可见就是设置m_bExitModalLoop这个标志位,使窗口退出。
之后就是GetMessage,TranslateMessage和DispatchMessage了,就完成了常见的消息处理。当我们创建窗口并运行在ModalMessageLoop函数当中时就形成了模态窗口的效果,也就是接管了消息的分发和处理,其他的窗口就被模住了。