在duilib中,可以调用CWindowWnd::ShowModal()来实现模态框的显示,该接口的代码如下所示:
UINT CWindowWnd::ShowModal()
{
ASSERT( ::IsWindow(m_hWnd) );
UINT nRet = 0;
HWND hWndParent = GetWindowOwner( m_hWnd );
::ShowWindow( m_hWnd, SW_SHOWNORMAL );
::EnableWindow( hWndParent, FALSE );
MSG msg = { 0 };
while( ::IsWindow(m_hWnd) && ::GetMessage(&msg, NULL, 0, 0) )
{
if( WM_CLOSE == msg.message && msg.hwnd == m_hWnd )
{
nRet = msg.wParam;
::EnableWindow( hWndParent, TRUE );
::SetFocus( hWndParent );
}
if( !CPaintManagerUI::TranslateMessage(&msg) )
{
::TranslateMessage( &msg );
::DispatchMessage( &msg );
}
if( WM_QUIT == msg.message )
{
break;
}
}
::EnableWindow( hWndParent, TRUE );
::SetFocus( hWndParent );
if( WM_QUIT == msg.message )
{
::PostQuitMessage( msg.wParam );
}
return nRet;
}
由代码可以看出,先将父窗口Disable掉,然后接管UI主线程的消息循环,在模态框关闭后,再将消息循环放归UI主线程。但在使用时要要稍微注意一下,下面就简单的说明一下。
先给出几段有问题的代码,先假设CDemoDlg是待显示的模态框窗口,由DUI派生而来,如下所示:
class CDemoDlg : public CWindowImplBase
{
public:
CDemoDlg( STRINGorID strUI, unsigned int dwTransparent = 255, bool bDeleteSelf = true );
virtual ~CDemoDlg();
......
}
代码段1如下所示:(下面的代码均是放置在某一个函数中,即在某一函数中弹出模态框)
CDemoDlg demoDlg( IDR_XML_DEMO_DLG );
demoDlg.Create( hParentWnd, _T("CDemoDlg"), UI_WNDSTYLE_BOX, UI_WNDSTYLE_EX_FRAME );
demoDlg.CenterWindow();
demoDlg.ShowModal();
代码中可以看出,CDemoDlg在创建时将使用默认值bool bDeleteSelf = true,所以在WindowImplBase::OnFinalMessage函数中窗口对象会自动被delete掉,看上去好像是没问题。实际上,demoDlg是局部对象,使用的是栈上的内存,但是delete删除的是堆上的内存,这肯定是有问题的,会引起异常。所以这种方法是有问题。
代码段2如下所示:
CDemoDlg* pDlg = new CDemoDlg ( IDR_XML_DEMO_DLG, 255, false );
pDlg->Create( hParentWnd, _T("CDemoDlg"), UI_WNDSTYLE_BOX, UI_WNDSTYLE_EX_FRAME );
pDlg->CenterWindow();
pDlg->ShowModal();
代码1中的自动销毁有问题,那我们就将bDeleteSelf设置为false,不让自动被销毁。但还是有问题,new出来的对象没有释放,会有内存泄漏,其实在ShowModal执行完后把new来的对象delete就好了。
那么如果不用new的方式,用代码1中的方式如何实现呢?也简单,构造对象时将bDeleteSelf设置为false,不让其自动被销毁,由于是局部变量,函数退出时会被销毁掉,即如下的代码:
CDemoDlg demoDlg( IDR_XML_DEMO_DLG,255, false );
demoDlg.Create( hParentWnd, _T("CDemoDlg"), UI_WNDSTYLE_BOX, UI_WNDSTYLE_EX_FRAME );
demoDlg.CenterWindow();
demoDlg.ShowModal();