1. 程式人生 > >DirectUI介面程式設計(五)WindowImplBase的使用

DirectUI介面程式設計(五)WindowImplBase的使用

上節筆者向大家介紹了Duilib的介面佈局並在最後編寫了一個仿QQ旋風的介面,但是由於我們遮蔽了系統的標題欄,讀者可能已經發現,我們的視窗沒辦法移動,同樣也不能通過拖動來改變視窗的大小。

這就需要我們對WM_NCHITTEST訊息進行處理,該訊息的LPARAM引數存放滑鼠的x座標和y座標,在程式中需要對x/y座標位置進行判斷,當座標落在下圖紅色線框位置時,我們向視窗過程函式返回HTCAPTION,這樣作業系統就會把紅色線框區域當成系統的標題欄。
這裡寫圖片描述

我們可以使用類似的方法告訴Windows作業系統哪裡是視窗的右下角,哪裡是視窗的邊框等等,關於這個訊息的更多介紹讀者可以參考MSDN。對該訊息進行處理算是比較麻煩的,而且對於初學者來說不太好理解,幸運的是Duilib官方為我們封裝好了一個WindowImplBase類,該類已經對一些Window訊息進行了處理,我們只需要繼承這個類就可以了。

筆者對該類稍微進行了修改,類的宣告寫在win_impl_base.hpp檔案中:

#ifndef WIN_IMPL_BASE_HPP
#define WIN_IMPL_BASE_HPP
#include "../DuiLib/StdAfx.h" 
#include <Windows.h>
#include <string>
typedef std::basic_string<TCHAR> tString;

using namespace DuiLib;

namespace DuiLib {
    class CWindowWnd;
    class
INotifyUI; class IMessageFilterUI; class IDialogBuilderCallback; } class WindowImplBase : public CWindowWnd, public INotifyUI, public IMessageFilterUI, public IDialogBuilderCallback { public: WindowImplBase(); virtual ~WindowImplBase(); virtual void OnFinalMessage(HWND hWnd); virtual UINT
GetClassStyle() const; virtual void Init(); virtual CControlUI* CreateControl(LPCTSTR pstrClass); virtual LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled); virtual LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); virtual LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); #if defined(WIN32) && !defined(UNDER_CE) virtual LRESULT OnNcActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); virtual LRESULT OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); virtual LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); virtual LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); virtual LRESULT OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); virtual LRESULT OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); #endif virtual LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); virtual LRESULT OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); virtual LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); virtual LRESULT OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); virtual LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); virtual LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); virtual LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); virtual LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); virtual LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam); virtual LRESULT HandleCustomMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); protected: virtual tString GetSkinFolder(); virtual tString GetSkinFile() = 0; virtual LRESULT ResponseDefaultKeyEvent(WPARAM wParam); protected: CPaintManagerUI paint_manager_; }; #endif // WIN_IMPL_BASE_HPP

下面是一些成員函式的實現部分,寫在win_impl_base.cpp檔案中:


#include "win_impl_base.hpp"

WindowImplBase::WindowImplBase()
{}

WindowImplBase::~WindowImplBase()
{}

UINT WindowImplBase::GetClassStyle() const
{
    return CS_DBLCLKS;
}

CControlUI* WindowImplBase::CreateControl(LPCTSTR pstrClass)
{
    return NULL;
}

void WindowImplBase::OnFinalMessage(HWND /*hWnd*/)
{
    paint_manager_.RemovePreMessageFilter(this);
    paint_manager_.RemoveNotifier(this);
    paint_manager_.ReapObjects(paint_manager_.GetRoot());
}

void WindowImplBase::Init()
{}

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

LRESULT WindowImplBase::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
    bHandled = FALSE;
    return 0;
}

#if defined(WIN32) && !defined(UNDER_CE)
LRESULT WindowImplBase::OnNcActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
    if( ::IsIconic(*this) ) bHandled = FALSE;
    return (wParam == 0) ? TRUE : FALSE;
}

LRESULT WindowImplBase::OnNcCalcSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
    return 0;
}

LRESULT WindowImplBase::OnNcPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
    return 0;
}

LRESULT WindowImplBase::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    POINT pt; pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam);
    ::ScreenToClient(*this, &pt);

    RECT rcClient;
    ::GetClientRect(*this, &rcClient);

    if( !::IsZoomed(*this) ) {
        RECT rcSizeBox = paint_manager_.GetSizeBox();
        if( pt.y < rcClient.top + rcSizeBox.top ) {
            if( pt.x < rcClient.left + rcSizeBox.left ) return HTTOPLEFT;
            if( pt.x > rcClient.right - rcSizeBox.right ) return HTTOPRIGHT;
            return HTTOP;
        }
        else if( pt.y > rcClient.bottom - rcSizeBox.bottom ) {
            if( pt.x < rcClient.left + rcSizeBox.left ) return HTBOTTOMLEFT;
            if( pt.x > rcClient.right - rcSizeBox.right ) return HTBOTTOMRIGHT;
            return HTBOTTOM;
        }
        if( pt.x < rcClient.left + rcSizeBox.left ) return HTLEFT;
        if( pt.x > rcClient.right - rcSizeBox.right ) return HTRIGHT;
    }

    RECT rcCaption = paint_manager_.GetCaptionRect();
    if( pt.x >= rcClient.left + rcCaption.left && pt.x < rcClient.right - rcCaption.right \
        && pt.y >= rcCaption.top && pt.y < rcCaption.bottom ) {
            CControlUI* pControl = static_cast<CControlUI*>(paint_manager_.FindControl(pt));
            if( pControl && _tcsicmp(pControl->GetClass(), _T("ButtonUI")) != 0 && 
                _tcsicmp(pControl->GetClass(), _T("OptionUI")) != 0 /*&&
                _tcsicmp(pControl->GetClass(), _T("TextUI")) != 0 */)
                return HTCAPTION;
    }

    return HTCLIENT;
}

LRESULT WindowImplBase::OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    MONITORINFO oMonitor = {};
    oMonitor.cbSize = sizeof(oMonitor);
    ::GetMonitorInfo(::MonitorFromWindow(*this, MONITOR_DEFAULTTOPRIMARY), &oMonitor);
    CRect rcWork = oMonitor.rcWork;
    rcWork.Offset(-rcWork.left, -rcWork.top);

    LPMINMAXINFO lpMMI = (LPMINMAXINFO) lParam;
    lpMMI->ptMaxPosition.x  = rcWork.left;
    lpMMI->ptMaxPosition.y  = rcWork.top;
    lpMMI->ptMaxSize.x      = rcWork.right;
    lpMMI->ptMaxSize.y      = rcWork.bottom;

    bHandled = FALSE;
    return 0;
}

LRESULT WindowImplBase::OnMouseWheel(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
    bHandled = FALSE;
    return 0;
}
#endif


LRESULT WindowImplBase::OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
    bHandled = FALSE;
    return 0;
}

LRESULT WindowImplBase::OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
    bHandled = FALSE;
    return 0;
}

LRESULT WindowImplBase::OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
    bHandled = FALSE;
    return 0;
}

LRESULT WindowImplBase::OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
    bHandled = FALSE;
    return 0;
}

LRESULT WindowImplBase::OnKeyDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
    bHandled = FALSE;
    return 0;
}

LRESULT WindowImplBase::OnKillFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
    bHandled = FALSE;
    return 0;
}

LRESULT WindowImplBase::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    SIZE szRoundCorner = paint_manager_.GetRoundCorner();
#if defined(WIN32) && !defined(UNDER_CE)
    if( !::IsIconic(*this) && (szRoundCorner.cx != 0 || szRoundCorner.cy != 0) ) {
        CRect rcWnd;
        ::GetWindowRect(*this, &rcWnd);
        rcWnd.Offset(-rcWnd.left, -rcWnd.top);
        rcWnd.right++; rcWnd.bottom++;
        HRGN hRgn = ::CreateRoundRectRgn(rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom, szRoundCorner.cx, szRoundCorner.cy);
        ::SetWindowRgn(*this, hRgn, TRUE);
        ::DeleteObject(hRgn);
    }
#endif
    bHandled = FALSE;
    return 0;
}


LRESULT WindowImplBase::OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    if (wParam == SC_CLOSE){
        bHandled = TRUE;
        return 0;
    }
#if defined(WIN32) && !defined(UNDER_CE)
    BOOL bZoomed = ::IsZoomed(*this);
    LRESULT lRes = CWindowWnd::HandleMessage(uMsg, wParam, lParam);
    if( ::IsZoomed(*this) != bZoomed ){
    }
#else
    LRESULT lRes = CWindowWnd::HandleMessage(uMsg, wParam, lParam);
#endif
    return lRes;
}


tString WindowImplBase::GetSkinFolder()
{
    return tString(CPaintManagerUI::GetInstancePath()); //+ _T("skin\\");
}

LRESULT WindowImplBase::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    LONG styleValue = ::GetWindowLong(*this, GWL_STYLE);
    styleValue &= ~WS_CAPTION;
    ::SetWindowLong(*this, GWL_STYLE, styleValue | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
    RECT rcClient;
    ::GetClientRect(*this, &rcClient);
    ::SetWindowPos(*this, NULL, rcClient.left, rcClient.top, rcClient.right - rcClient.left, \
        rcClient.bottom - rcClient.top, SWP_FRAMECHANGED);

    paint_manager_.Init(m_hWnd);
    paint_manager_.AddPreMessageFilter(this);

    CDialogBuilder builder; 
    //paint_manager_.SetResourcePath(GetSkinFolder().c_str()); 
    //tString tstrSkin = paint_manager_.GetResourcePath();
    tString tstrSkin = GetSkinFile(); 
    CControlUI* pRoot = builder.Create(tstrSkin.c_str(), (UINT)0, this, &paint_manager_);
    paint_manager_.AttachDialog(pRoot);
    paint_manager_.AddNotifier(this);

    Init();
    return 0;
}

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

LRESULT WindowImplBase::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    LRESULT lRes = 0;
    BOOL bHandled = TRUE;
    switch (uMsg)
    {
    case WM_CREATE:         lRes = OnCreate(uMsg, wParam, lParam, bHandled); break;
    case WM_CLOSE:          lRes = OnClose(uMsg, wParam, lParam, bHandled); break;
    case WM_DESTROY:        lRes = OnDestroy(uMsg, wParam, lParam, bHandled); break;
#if defined(WIN32) && !defined(UNDER_CE)
    case WM_NCACTIVATE:     lRes = OnNcActivate(uMsg, wParam, lParam, bHandled); break;
    case WM_NCCALCSIZE:     lRes = OnNcCalcSize(uMsg, wParam, lParam, bHandled); break;
    case WM_NCPAINT:        lRes = OnNcPaint(uMsg, wParam, lParam, bHandled); break;
    case WM_NCHITTEST:      lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); break;
    case WM_GETMINMAXINFO:  lRes = OnGetMinMaxInfo(uMsg, wParam, lParam, bHandled); break;
    case WM_MOUSEWHEEL:     lRes = OnMouseWheel(uMsg, wParam, lParam, bHandled); break;
#endif
    case WM_SIZE:           lRes = OnSize(uMsg, wParam, lParam, bHandled); break;   
    case WM_SYSCOMMAND:     lRes = OnSysCommand(uMsg, wParam, lParam, bHandled); break;
    case WM_KEYDOWN:        lRes = OnKeyDown(uMsg, wParam, lParam, bHandled); break;
    case WM_KILLFOCUS:      lRes = OnKillFocus(uMsg, wParam, lParam, bHandled); break;
    case WM_SETFOCUS:       lRes = OnSetFocus(uMsg, wParam, lParam, bHandled); break;
    case WM_LBUTTONUP:      lRes = OnLButtonUp(uMsg, wParam, lParam, bHandled); break;
    case WM_LBUTTONDOWN:    lRes = OnLButtonDown(uMsg, wParam, lParam, bHandled); break;
    case WM_MOUSEMOVE:      lRes = OnMouseMove(uMsg, wParam, lParam, bHandled); break;
    default:                bHandled = FALSE; break;
    }
    if (bHandled) return lRes;

    lRes = HandleCustomMessage(uMsg, wParam, lParam, bHandled);
    if (bHandled) return lRes;

    if (paint_manager_.MessageHandler(uMsg, wParam, lParam, lRes)) return lRes;
    return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
}

LRESULT WindowImplBase::MessageHandler(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/, bool& /*bHandled*/)
{
    if (uMsg == WM_KEYDOWN)
    {
        switch (wParam)
        {
        case VK_RETURN:
        case VK_ESCAPE:
            return ResponseDefaultKeyEvent(wParam);
        default:
            break;
        }
    }
    return FALSE;
}

LRESULT WindowImplBase::ResponseDefaultKeyEvent(WPARAM wParam)
{
    if (wParam == VK_RETURN)
    {
        return FALSE;
    }
    else if (wParam == VK_ESCAPE)
    {
        Close();
        return TRUE;
    }

    return FALSE;
}

我們需要將這兩個檔案新增到自己的工程中,專案結構如下圖所示:
這裡寫圖片描述

在我們的程式中不再繼承CWindowWnd和INotifyUI這兩個類,而是直接繼承WindowImplBase,重寫父類的GetWindowClassName、GetClassStyle、GetSkinFile、Notify四個函式即可:

#include "win_impl_base.hpp"
#include <Windows.h>
class MyWnd : public WindowImplBase
{
    LPCTSTR GetWindowClassName() const
    {
        return L"MyWnd";
    }
    UINT GetClassStyle() const{
        return UI_CLASSSTYLE_FRAME|CS_DBLCLKS;
    }
    tString GetSkinFile(){
        return L"tutorial5.xml";
    }
    void Notify(TNotifyUI& msg)
    {
        if(msg.sType == L"click")
        {
            if(msg.pSender->GetName() == L"CloseBtn")
            {
                ::PostQuitMessage(0);

            }else if(msg.pSender->GetName() == L"MinBtn")
            {
                ::SendMessage(m_hWnd,WM_SYSCOMMAND, SC_MINIMIZE, 0);
            }
        }
    } 


};
INT WinMain(HINSTANCE hInst,HINSTANCE hPreInst,LPSTR lpCmdLine,INT Show)
{
    CPaintManagerUI::SetInstance(hInst);
    CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetResourcePath());
    //建立主視窗
    MyWnd* pFrame = new MyWnd();
    pFrame->Create(NULL,L"Tutorial5",UI_WNDSTYLE_FRAME^WS_THICKFRAME,WS_EX_WINDOWEDGE);
    pFrame->CenterWindow(); 
    pFrame->ShowWindow(true);
    CPaintManagerUI::MessageLoop();

    return 0;
}

我們只需要在GetSkinFile方法中返回一個介面佈局檔名稱,比上節簡單多了吧,編譯執行看到上節的介面能夠成功載入而且已經可以拖動了。
這裡寫圖片描述