模态对话框的实现原理
- 格式:docx
- 大小:39.49 KB
- 文档页数:7
MFC 模态对话框的实现原理
1人收藏此文章, 发表于10个月前(2012-09-30 11:20) , 已有471次阅读,共1个评论
1. 模态对话框
在涉及GUI程序开发的过程中,常常有模态对话框以及非模态对话框的概念
模态对话框:在子界面活动期间,父窗口是无法进行消息响应。独占用户输入非模态对话框:各窗口之间不影响
主要区别:非模态对话框与APP共用消息循环,不会独占用户。
模态对话框独占用户输入,其他界面无法响应
在用户层的主要逻辑如下:
TestDlg dlg;
if (dlg.DoModal() == IDOK)
{
//处理完毕后的操作
}
.......//后续处理
在具体实现中,有如下几个步骤:
1. 让父窗口失效EnableWindow(parentWindow, FALSE)
2. 建立模态对话框自己的消息循环(RunModalLoop)
3. 直至接收关闭消息,消息循环终止,并销毁窗口。
INT_PTR CDialog::DoModal()
{
//对话框资源加载
......
//在创建模态窗口之前先让父窗口失效,不响应键盘、鼠标产生的消息
HWND hWndParent = PreModal();
AfxUnhookWindowCreate();
BOOL bEnableParent = FALSE;
if (hWndParent && hWndParent != ::GetDesktopWindow()
&& ::IsWindowEnabled(hWndParent))
{
::EnableWindow(hWndParent, FALSE);
bEnableParent = TRUE;
.......
}
//创建模态窗口,并进行消息循环,若窗口不关闭,则循环不退出
AfxHookWindowCreate(this);
VERIFY(RunModalLoop(dwFlags) == m_nModalResult);
//窗口关闭,销毁窗口
DestroyWindow();
PostModal();
//释放资源,并让父窗口有效
pMainWnd->EnableWindow(TRUE);
//返回
return m_nModalResult;
}
2. 模态窗口中的消息循环
int CWnd::RunModalLoop(DWORD dwFlags)
{
//要检查窗口状态是否是模态窗口
//若状态一直为模态,则一直进行消息循环
for (;;)
{
ASSERT(ContinueModal());
// phase1: check to see if we can do idle work
while (bIdle &&
!::PeekMessage(pMsg, NULL, NULL, NULL,
PM_NOREMOVE))
{
ASSERT(ContinueModal());
// show the dialog when the message queue goes idle
if (bShowIdle)
{
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
bShowIdle = FALSE;
}
// call OnIdle while in bIdle state
if (!(dwFlags & MLF_NOIDLEMSG) && hWndParent != NULL && lIdleCount == 0)
{
// send WM_ENTERIDLE to the parent
::SendMessage(hWndParent,
WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)m_hWnd);
}
if ((dwFlags & MLF_NOKICKIDLE) ||
!SendMessage(WM_KICKIDLE,
MSGF_DIALOGBOX, lIdleCount++))
{
// stop idle processing next time
bIdle = FALSE;
}
}
//在有消息的情况下取消息处理
do
{
ASSERT(ContinueModal());
// pump message, but quit on WM_QUIT
if (!AfxPumpMessage())
{
AfxPostQuitMessage(0);
return -1;
}
// show the window when certain special messages rec'd
if (bShowIdle &&
(pMsg->message == 0x118 || pMsg->message == WM_SYSKEYDOWN))
{
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
bShowIdle = FALSE;
}
if (!ContinueModal())