您的位置:首页 > 产品设计 > UI/UE

DirectUI界面编程(五)WindowImplBase的使用

2015-07-26 21:57 507 查看
上节笔者向大家介绍了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方法中返回一个界面布局文件名称,比上节简单多了吧,编译运行看到上节的界面能够成功加载而且已经可以拖动了。



博文源码:https://github.com/rongbo-j/duilib-tutorial
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: