前言
duilib程序中,编写自己的窗口类一般的继承关系有两种,一种是继承自CWindowWnd、INotifyUI、IMessageFilterUI,而第二种方式是继承自duilib封装好的通用窗口类WindowImplBase。
1、WindowImplBase类
从源码中可以看到WindowImplBase其实是继承自一般能用到的所有基础类:
#ifndef WIN_IMPL_BASE_HPP
#define WIN_IMPL_BASE_HPP
namespace DuiLib
{
enum UILIB_RESOURCETYPE
{
UILIB_FILE=1, // 来自磁盘文件
UILIB_ZIP, // 来自磁盘zip压缩包
UILIB_RESOURCE, // 来自资源
UILIB_ZIPRESOURCE, // 来自资源的zip压缩包
};
class DUILIB_API WindowImplBase
: public CWindowWnd
, public CNotifyPump
, public INotifyUI
, public IMessageFilterUI
, public IDialogBuilderCallback
{
public:
WindowImplBase(){};
virtual ~WindowImplBase(){};
virtual void InitWindow(){};
virtual void OnFinalMessage( HWND hWnd );
virtual void Notify(TNotifyUI& msg);
DUI_DECLARE_MESSAGE_MAP()
virtual void OnClick(TNotifyUI& msg);
protected:
virtual CDuiString GetSkinFolder() = 0;
virtual CDuiString GetSkinFile() = 0;
virtual LPCTSTR GetWindowClassName(void) const = 0 ;
virtual LRESULT ResponseDefaultKeyEvent(WPARAM wParam);
CPaintManagerUI m_PaintManager;
static LPBYTE m_lpResourceZIPBuffer;
public:
virtual UINT GetClassStyle() const;
virtual UILIB_RESOURCETYPE GetResourceType() const;
virtual CDuiString GetZIPFileName() const;
virtual LPCTSTR GetResourceID() const;
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);
virtual LRESULT OnMouseHover(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
#endif
virtual LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
virtual LRESULT OnChar(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);
virtual LONG GetStyle();
};
}
#endif // WIN_IMPL_BASE_HPP
2、优点
从上可以看到,一般编写自己的duilib窗口类所需要继承的几个类都已经被WindowImplBase继承了,而且已经做了部分封装,这样我们直接继承WindowImplBase不是方便了很多,而且只需要实现以下几个函数即可实现简单的duilib窗口,很简洁方便:
virtual CDuiString GetSkinFolder() = 0;
virtual CDuiString GetSkinFile() = 0;
virtual LPCTSTR GetWindowClassName(void) const = 0 ;
3、缺点
WindowImplBase通用窗口类目前不完全统计bug较多,好多地方需要自己修改,这个就要根据自己的需求不同自己去调整该类的源码,达到自己想要的效果。
4、示例
下面实现一个简单的例子:
MainFrame.h:
#include "resource.h"
class CMainFrame : public WindowImplBase
{
public:
CMainFrame();
~CMainFrame();
public:
LPCTSTR GetWindowClassName() const;
virtual CDuiString GetSkinFile();
virtual CDuiString GetSkinFolder();
virtual LRESULT HandleCustomMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
public:
protected:
void Notify(TNotifyUI& msg);
bool OnBtnClickOfEnter(TNotifyUI& msg);
};
MainFrame.cpp:
#include "stdafx.h"
#include "MainFrame.h"
#include "DefControlName.h"
#include "PersonalCenterDialog.h"
HWND g_hMainFrame = NULL;
CMainFrame::CMainFrame()
{
}
CMainFrame::~CMainFrame()
{
PostQuitMessage(0);
}
LPCTSTR CMainFrame::GetWindowClassName() const
{
return _T("App");
}
CDuiString CMainFrame::GetSkinFile()
{
return _T("MainFrame.xml");
}
CDuiString CMainFrame::GetSkinFolder()
{
return _T("skin\\");
}
//duilib自身消息
void CMainFrame::Notify(TNotifyUI& msg)
{
if (_tcsicmp(msg.sType, _T("windowinit")) == 0)
{
}
else if (_tcsicmp(msg.sType, _T("killfocus")) == 0)
{
}
else if (_tcsicmp(msg.sType, _T("click")) == 0)
{
if (_tcsicmp(msg.pSender->GetName(), kMainFrameBtnClose) == 0)
{
Close();
}
else if (_tcsicmp(msg.pSender->GetName(), kMainFrameBtnEnter) == 0)
{
OnBtnClickOfEnter(msg);
}
}
else if (_tcsicmp(msg.sType, _T("timer")) == 0)
{ }
else if (_tcsicmp(msg.sType, _T("selectchanged")) == 0)
{ }
else if (_tcsicmp(msg.sType, _T("itemactivate")) == 0)
{ }
else if (_tcsicmp(msg.sType, _T("itemclick")) == 0)
{ }
}
bool CMainFrame::OnBtnClickOfEnter(TNotifyUI & msg)
{
CPersonalCenterDialog* pDialog = new CPersonalCenterDialog();
if (pDialog == NULL)
return false;
DWORD dwStyle = UI_WNDSTYLE_FRAME;
dwStyle = dwStyle^WS_MAXIMIZEBOX;
#if defined(WIN32) && !defined(UNDER_CE)
pDialog->Create(NULL, _T("个人中心"), dwStyle | WS_POPUP, NULL, 0, 0, 0, 0);
#else
pDialog->Create(NULL, _T("个人中心"), dwStyle | WS_POPUP, NULL, 0, 0, 0, 0);
#endif
pDialog->CenterWindow();
::ShowWindow(g_hMainFrame, SW_HIDE);
::ShowWindow(*pDialog, SW_SHOW);
return true;
}
//处理自定义消息
LRESULT CMainFrame::HandleCustomMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
switch (uMsg)
{
/*case WM_APPOBD_MSG_SHOW_MAIN_FRAME:
{
::ShowWindow(m_hWnd, SW_SHOW);
break;
}*/
default:
break;
}
return 0;
}
//处理事件消息
LRESULT CMainFrame::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DEVICECHANGE:
{
break;
}
//case WM_CLOSE:
// PostQuitMessage(0);
// break;
default:
break;
}
return WindowImplBase::HandleMessage(uMsg, wParam, lParam);
}
stdafx.h:
// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // 从 Windows 头中排除极少使用的资料
// Windows 头文件:
#include <windows.h>
#include "..\DuiLib\UIlib.h"
using namespace DuiLib;
#ifdef _DEBUG
# ifdef _UNICODE
# pragma comment(lib, "..\\Lib\\DuiLib_ud.lib")
# else
# pragma comment(lib, "..\\Lib\\DuiLib_d.lib")
# endif
#else
# ifdef _UNICODE
# pragma comment(lib, "..\\Lib\\DuiLib_u.lib")
# else
# pragma comment(lib, "..\\Lib\\DuiLib.lib")
# endif
#endif
extern HWND g_hMainFrame;
// TODO: 在此处引用程序需要的其他头文件
main.cpp :
#include "stdafx.h"
#include "MainFrame.h"
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int nCmdShow)
{
CPaintManagerUI::SetInstance(hInstance);
CWndShadow::Initialize(hInstance);
CMainFrame* pFrame = new CMainFrame();
if (pFrame == NULL)
return 0;
DWORD dwStyle = UI_WNDSTYLE_FRAME;
dwStyle = dwStyle^WS_MAXIMIZEBOX;
pFrame->Create(NULL, _T("云端软件"), dwStyle, WS_EX_STATICEDGE | WS_EX_APPWINDOW, 1, 1, 0, 0); //倒数第3第4个参数可以设置duilib左上角的坐标,倒数第1第2个参数因为继承了WindowImpBase,
//WindowImpBase类中在创建窗口大小时会取xml文件中的窗口大小数据,顾此处两个参数值无效。
pFrame->CenterWindow();
::ShowWindow(*pFrame, SW_SHOW);
CPaintManagerUI::MessageLoop(); //消息循环
::CoUninitialize();
return 0;
}
5、TNotifyUI事件消息结构体解释
// Structure for notifications to the outside world
typedef struct tagTNotifyUI
{
CDuiString sType;
CDuiString sVirtualWnd;
CControlUI* pSender;
DWORD dwTimestamp;
POINT ptMouse;
WPARAM wParam;
LPARAM lParam;
} TNotifyUI;
TNotifyUI结构体是用于传递通知消息的数据结构。它包含了一些成员变量,用于在Notify函数中传递事件消息的相关信息。以下是TNotifyUI结构体的成员变量及其解释:
-
TNotifyUI::pSender:
类型:CControlUI*
解释:指向触发通知消息的控件的指针。通过这个成员变量,你可以知道是哪个控件触发了当前的通知消息。 -
TNotifyUI::sType:
类型:LPCTSTR
解释:表示通知消息的类型。通常,开发者可以根据这个成员变量来判断当前通知消息的类型,然后执行相应的操作。 -
TNotifyUI::wParam:
类型:WPARAM
解释:消息的附加参数,用于传递额外的数据。具体的含义取决于不同的通知消息类型。 -
TNotifyUI::lParam:
类型:LPARAM
解释:消息的附加参数,用于传递额外的数据。具体的含义取决于不同的通知消息类型。 -
TNotifyUI::ptMouse:
类型:POINT
解释:表示鼠标在触发通知消息的控件上的位置。通常在处理鼠标事件时会使用到这个成员变量。 -
TNotifyUI::wKeyState:
类型:WORD
解释:表示当前键盘的状态,例如是否按下了Ctrl、Shift、Alt等键。在处理键盘事件时,可以使用这个成员变量。 -
TNotifyUI::dwTimestamp:
类型:DWORD
解释:表示通知消息的时间戳,即消息发生的时间。在某些情况下,你可能需要知道消息发生的时间。
TNotifyUI结构体中的成员变量提供了处理通知消息所需的基本信息,你可以根据具体的通知消息类型和需求,使用这些成员变量来执行相应的操作。在处理消息时,通常会先判断通知消息的类型(通过sType成员变量),然后根据需要使用wParam和lParam来传递数据或执行特定的逻辑。
typedef struct tagTNotifyUI 是一个定义了TNotifyUI结构体的类型别名。
TNotifyUI结构体是在DuiLib中用于传递通知消息的数据结构。它包含了以下成员变量:
-
CDuiString sType:
类型:CDuiString
解释:表示通知消息的类型。通常,开发者可以根据这个成员变量来判断当前通知消息的类型,然后执行相应的操作。 -
CDuiString sVirtualWnd:
类型:CDuiString
解释:表示虚拟窗口的名称。在DuiLib中,虚拟窗口用于区分不同的UI界面,每个UI界面都有一个唯一的虚拟窗口名称。 -
CControlUI* pSender:
类型:CControlUI*
解释:指向触发通知消息的控件的指针。通过这个成员变量,你可以知道是哪个控件触发了当前的通知消息。 -
DWORD dwTimestamp:
类型:DWORD
解释:表示通知消息的时间戳,即消息发生的时间。在某些情况下,你可能需要知道消息发生的时间。 -
POINT ptMouse:
类型:POINT
解释:表示鼠标在触发通知消息的控件上的位置。通常在处理鼠标事件时会使用到这个成员变量。 -
WPARAM wParam:
类型:WPARAM
解释:消息的附加参数,用于传递额外的数据。具体的含义取决于不同的通知消息类型。 -
LPARAM lParam:
类型:LPARAM
解释:消息的附加参数,用于传递额外的数据。具体的含义取决于不同的通知消息类型。
TNotifyUI结构体中的成员变量提供了处理通知消息所需的基本信息。你可以根据具体的通知消息类型和需求,使用这些成员变量来执行相应的操作。在处理消息时,通常会先判断通知消息的类型(通过sType成员变量),然后根据需要使用wParam和lParam来传递数据或执行特定的逻辑。