平行世界

电影、优惠券分享网站-mylofter.com

Duilib子窗口-关闭&设置位置

在处理duilib子窗口,往往会遇到如下情况:

  1. 子窗口在主窗口下面,两个窗口独立,不互相影响,即可以同时对主窗口和子窗口进行操作。
  2. 关闭子窗口的时候,主窗口也直接关闭了。

参考文章:

http://blog.csdn.net/u012519333/article/details/42146257

http://www.cnblogs.com/youyipin/p/5550445.html


子窗口在主窗口下面,两个窗口独立,不互相影响,即可以同时对主窗口和子窗口进行操作。

void CMainDlg::DoTask()
{
CTaskDlg * pDlg = NULL;

pDlg = new CTaskDlg(XML_FILE_NAME_TASK_DLG, WND_CLASS_NAME_TASK_DLG);
pDlg->Create(this->m_hWnd, MAIN_RORG_DISP_NAME, UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE); ///< 如果参数1是NULL, 为桌面, 子窗口就不是模态对话框
pDlg->CenterWindow();
pDlg->ShowModal(); ///< 弹出的是模态窗口
}

pDlg->Create 的参数1,开始写成了NULL, 子窗口弹出后, 还可以操作主窗口.

因为要弹出模态对话框, 跟进 pDlg->ShowModal(),  看到了duilib禁止主窗口的代码,  才想到参数1应为父窗口窗口句柄.

可以看出, 当要弹出非模态窗口时, 可以将pDlg->Create 的参数1 填成 NULL.

UINT CWindowWnd::ShowModal()
{
ASSERT(::IsWindow(m_hWnd));
UINT nRet = 0;
HWND hWndParent = GetWindowOwner(m_hWnd); ///< 如果子窗口创建时,参数1为NULL, 这里得到的 hWndParent 就为 NULL
::ShowWindow(m_hWnd, SW_SHOWNORMAL);
::EnableWindow(hWndParent, FALSE); ///< 当 (NULL == hWndParent) 时, EnableWindow 不生效, 导致弹出的是非模态窗口.
MSG msg = { 0 };
while( ::IsWindow(m_hWnd) && ::GetMessage(&msg, NULL, 0, 0) ) {
if( msg.message == WM_CLOSE && msg.hwnd == m_hWnd ) {
nRet = msg.wParam;
::EnableWindow(hWndParent, TRUE);
::SetFocus(hWndParent);
}
if( !CPaintManagerUI::TranslateMessage(&msg) ) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
if( msg.message == WM_QUIT ) break;
}
::EnableWindow(hWndParent, TRUE);
::SetFocus(hWndParent);
if( msg.message == WM_QUIT ) ::PostQuitMessage(msg.wParam);
return nRet;
}

关闭子窗口的时候,主窗口也直接关闭了。

自己在学习Duilib时,学习ListDemo中的右键生成菜单,然后当菜单被点击活着失去焦点时,这个菜单窗口如何销毁的问题。

1、在这里,创建菜单时使用了子窗口的概念,创建时,使用了WS_EX_TOOLWINDOW类型,表示是一个工具栏窗口。

2、这个菜单窗口有自己的消息处理函数HandleMessage。第一次的尝试是调用CWindowWnd中的Close函数,查看了这个函数的源码,发现其中是使用PostMessage给自己发送了一个WM_CLOSE的消息,然后在HandleMessage中拦截WM_CLOSE的消息,在消息处理函数中调用了PostQuitMessage(0),此种情况下,菜单窗口是退出了,但是父窗口也是跟着退出了。因为在CPaintManager的MessageLoop中的GetMessage,当收到WM_QUIT的消息时会返回0,此时,MessageLoop中的while循环就会给打破。整个消息循环就会退出,因此整个程序退出

3、第二次的尝试,是直接在菜单项被选中和菜单窗口失去焦点时调用PostQuitMessage(0),由于跟第一次尝试是换汤不换药的动作,因此也已失败告终。

4、由于前两次的失败,然后再网上各种查询也未找到相关的解决方法。后来在查看MSDN时,查看了消息WM_CLOSE的Remark,其中说道“应用程序通过处理WM_CLOSE消息,可以在窗口销毁前对用户做一些提示,如果用户确认提示的话,通过调用DestoryWindow来销魂窗口”。因此,此基础和第一二次尝试的基础上,对代码进行了修改。首先,在菜单项被选中和菜单窗口失去焦点时调用CWindowWnd的Close函数,然后在窗口的消息处理函数中拦截WM_CLOSE消息,在WM_CLOSE的消息处理函数中通过使用DestoryWindow来达到销毁菜单窗口的目的,在调用了DestoryWindow后,再调用delete this来删除窗体本身。这样才达到了效果。

当然,在做完第4步时,也遇到了其他的一些小麻烦,稍作调试即完成。也算对window应用编程又有了点新的体会。主要的代码如下:

LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
bHandled = FALSE;
return 0;
}

LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
//::PostQuitMessage(0L); //不发送退出消息,OnClose中也是如此

bHandled = FALSE;
return 0;
}

LRESULT OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (wParam == SC_CLOSE) {
bHandled = TRUE;
SendMessage(WM_CLOSE);
return 0;
}
BOOL bZoomed = ::IsZoomed(*this);
LRESULT lRes = CWindowWnd::HandleMessage(uMsg, wParam, lParam);
if (::IsZoomed(*this) != bZoomed) {
if (!bZoomed) {
CControlUI* pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("maxbtn")));
if (pControl) pControl->SetVisible(false);
pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("restorebtn")));
if (pControl) pControl->SetVisible(true);
}
else {
CControlUI* pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("maxbtn")));
if (pControl) pControl->SetVisible(true);
pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("restorebtn")));
if (pControl) pControl->SetVisible(false);
}
}
return lRes;
}

virtual void Notify(TNotifyUI& msg) {
if (msg.sType == _T("click"))
{
if (msg.pSender == m_pCloseBtn) {
Close(IDOK);
return;
}
}
}

 

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注