1 Duilib软件界面出现不可拖动不可拉伸的问题

距离上一次用Duilib写Windows软件界面已经几个月了,对于Duilib的使用难免比较生疏,今天就遇到一个比较费解的问题,一般情况下我们在写duilib界面的xml文件时,会如下的对软件主界面进行定义

<Window size="1280,720" maxinfo="1280,720" mininfo="1280,720" sizebox="6,6,6,6" caption="0,0,0,90" showshadow="true" shadowsize="2" shadowposition="0,0" shadowcolor="#F0F0F0" shadowdarkness="155" >
</Window>

其中Window的sizebox属性定义软件窗口可拖动改变窗口大小的边距,而caption定义窗口可拖动的标题栏大小的边距,一般情况下,如果我们在界面xml文件中按上述方式定义了这两个属性,那么我们就可以通过鼠标按住软件进行拖动,和将鼠标放在软件四个边界对界面进行拖动拉伸,但是今天即使定义了上述的两个属性,也无法正常的对界面进行拖动和拉伸。

在经过费解和查找问题之后,是由于我对WindowImplBase类的虚函数OnSysCommand进行了实现,但是并没有在其中有任何代码实现,这直接导致了后续没有办法对消息进行正常的处理,在WindowImplBase中,OnSysCommand的实现如下

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

如果我们要自定义实现,但是其中并没有使用CWindowWnd::HandleMessage(uMsg, wParam, lParam);对系统消息进行处理,那么久会导致出现上述的问题,所以解决方法有两种,第一种就是直接使用WindowImplBase类的虚函数OnSysCommand实现,不进行复写;第二种就是如果一定要复写的情况下,一定要将CWindowWnd::HandleMessage(uMsg, wParam, lParam);放在函数体中,比如

LRESULT MainWindow::OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    // 有时会在收到WM_NCDESTROY后收到wParam为SC_CLOSE的WM_SYSCOMMAND
    if (wParam == SC_CLOSE) {
        ::PostQuitMessage(0L);
        bHandled = TRUE;
        return 0;
    }

    BOOL bZoomed = ::IsZoomed(*this);
    LRESULT lRes = CWindowWnd::HandleMessage(uMsg, wParam, lParam);
}

出现这种情况还是由于自己已经很久不写了,以后要多注意这种细节问题。