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

IM 开源项目 客户端UI框架 Direct UI

2012-01-06 12:01 405 查看
客户端

目前客户端的实现,不少大公司采用了较为新潮的Direct UI技术,本项目中也考虑使用Direct UI,但可惜微软并没有提供可使用的Direct UI 封装,因此我们自己设计实现Direct UI,并在此基础上实现客户端UI部分的功能。

Direct UI 框架的实现并不复杂,就是繁琐,如抽象窗口,控件自绘制,设计完成消息循环与映射,资源管理...

CWinWnd: 注册创建主窗口,也是唯一具备Win 窗口句柄的窗口,其他一切控件子窗口,均绘制在此窗口上,维持逻辑存在。

具体实现如下:

头文件:

#ifndef H_WINWND_H
#define H_WINWND_H
#include "CTypeDef.h"
#include "UIStructDef.h"
#include "UIMSGMgr.h"
#include <map>

class CWinWnd : public IWinWnd
{
public:
CWinWnd(void);
virtual ~CWinWnd(void);

BOOL RegWinClass( HINSTANCE hInstance = NULL);														// 注册窗口类

HWND Create(HWND ahwndParent, LPCTSTR apstrName, DWORD adwStyle, DWORD adwExStyle,					// 创建窗口
const RECT arc, HMENU ahMenu = NULL, HINSTANCE hInstance = NULL);

HWND Create(HWND ahwndParent, LPCTSTR apstrName, DWORD adwStyle, DWORD adwExStyle,					// 创建窗口
int ax = CW_USEDEFAULT, int ay = CW_USEDEFAULT, int acx = CW_USEDEFAULT,
int acy = CW_USEDEFAULT, HMENU ahMenu = NULL, HINSTANCE hInstance = NULL);

void SetWndInfo(HINSTANCE ahInstance, ULong aulStyle,ULong aulStyleEx, int aiXVertex, int aiYVertex, int aiWeigth, int aiHeigth, HMENU ahMenu = NULL);				// 设置大小信息

void ShowWindow(BOOL bShow /*= true*/, BOOL bTakeFocus /*= false*/);								// 显示窗口
static LRESULT CALLBACK
__WndProc(HWND ahWnd, UINT auMsg, WPARAM awParam, LPARAM alParam);								// 消息回调 
HWND Subclass(HWND hWnd);																			// 子类化
void Unsubclass(void);																				// 反子类化
void SetIcon(UINT nRes);																			// 设置图标
void CenterWindow(void);																			// 居中
void Close(UINT nRet);																				// 关闭
UINT ShowModal(void);																				// ???

//protected:
protected:
virtual LRESULT
HandleMessage(UINT auMsg, WPARAM awParam, LPARAM alParam);										// 消息处理
virtual void
OnFinalMessage(HWND ahWnd);																		// 退出
virtual void
SetWinClassName(TCHAR* apClassName);															// 设置注册类名称
virtual LPCTSTR
GetWinClassName(void) const;																	// 获得注册类名称
virtual void
SetWinName(TCHAR* apClassName);																	// 设置窗口名称
virtual LPCTSTR
GetWinName(void) const;																			// 获得窗口名称
virtual void
SetXmlFile(TCHAR* apXmlFile);																	// 设置Xml文件名称
virtual LPCTSTR
GetXmlFile(void) const;																			// 获得Xml文件名称

protected:
HWND			m_hWnd;																				// 窗口句柄
WNDPROC			m_OldWndProc;																		// 旧的消息回调
bool			m_bSubclassed;																		// 子窗口
TCHAR			m_lszRegClassName[MAX_PATH+1];														// 窗口注册类名称
TCHAR			m_lszWndName[MAX_PATH+1];															// 窗口名称
TCHAR			m_szXmlFile[MAX_PATH+1];																// 界面配置文件名称

TCHAR			m_lszInstancePath[MAX_PATH+1];
TCHAR			m_lszCurPath[MAX_PATH+1];

CMSGMgr			m_oMsgMgr;																			// 对象消息处理
CUIBaseCtrl*	m_pRootCtrl;																		// 根控件
CUICache*		m_pUICache;																			// 界面资源缓存

int				m_iXVertex;
int				m_iYVertex;
int				m_iWeigth;
int				m_iHeigth;
HMENU			m_hMenu;
ULong			m_ulStyle;
ULong			m_ulStyleEx;
HINSTANCE		m_hInstance;
};
#endif//H_WINWND_H


实现文件:

#include "StdAfx.h"
#include "UIWinWnd.h"
#include <afxwin.h>

CWinWnd::CWinWnd(void)
: m_hWnd(NULL)
, m_OldWndProc(::DefWindowProc)
, m_iXVertex(CW_USEDEFAULT)
, m_iYVertex(CW_USEDEFAULT)
, m_iWeigth(CW_USEDEFAULT)
, m_iHeigth(CW_USEDEFAULT)
, m_hMenu(NULL)
, m_hInstance(NULL)
, m_pUICache(NULL)

{
memset(m_lszRegClassName, 0, sizeof(TCHAR)*(MAX_PATH+1));
memset(m_lszInstancePath, 0, sizeof(TCHAR)*(MAX_PATH+1));
memset(m_lszCurPath, 0, sizeof(TCHAR)*(MAX_PATH+1));
memset(m_lszWndName, 0, sizeof(TCHAR)*(MAX_PATH+1));
memset(m_szXmlFile, 0, sizeof(TCHAR)*(MAX_PATH+1));
m_pUICache = CUICache::GetSigoObj();
}

CWinWnd::~CWinWnd(void)
{
}

LRESULT CALLBACK CWinWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CWinWnd* pThis = NULL;
if( uMsg == WM_NCCREATE )
{
LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
pThis = static_cast<CWinWnd*>(lpcs->lpCreateParams);

if (pThis)
{
pThis->m_hWnd = hWnd;
::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));
}
}
else
{
pThis = reinterpret_cast<CWinWnd*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
if( uMsg == WM_NCDESTROY && pThis != NULL )
{
LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);
::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L);

if( pThis->m_bSubclassed )
{
// pThis->Unsubclass();
}

pThis->m_hWnd = NULL;
pThis->OnFinalMessage(hWnd);
return lRes;
}
}
if( pThis != NULL )
return pThis->HandleMessage(uMsg, wParam, lParam);
else
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}

LRESULT CWinWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return ::CallWindowProc(m_OldWndProc, m_hWnd, uMsg, wParam, lParam);
}

void CWinWnd::OnFinalMessage(HWND /*hWnd*/)
{
}

// 注册窗口类
BOOL CWinWnd::RegWinClass(HINSTANCE hInstance)
{
m_hInstance = hInstance;
if (!m_pUICache)
return FALSE;

m_pUICache->SetInstance(hInstance);
// 初始化应用程序路径
m_pUICache->GetInstancePath(m_lszInstancePath);
m_pUICache->SetResPackPath(m_lszInstancePath);
m_pUICache->GetCurrentPath(m_lszCurPath);

WNDCLASS wc = {0};
wc.style = CS_DBLCLKS;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hIcon = NULL;
wc.lpfnWndProc = CWinWnd::__WndProc;
wc.hInstance = hInstance;
wc.hInstance = NULL;
wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName  = NULL;
wc.lpszClassName = GetWinClassName();
ATOM ret = ::RegisterClass(&wc);
ASSERT((NULL !=  ret)  || (::GetLastError()==ERROR_CLASS_ALREADY_EXISTS));
return (ret != NULL) || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
}

HWND CWinWnd::Create(HWND ahwndParent, LPCTSTR apstrName, DWORD adwStyle, DWORD adwExStyle, const RECT arc, HMENU ahMenu, HINSTANCE hInstance)
{
return Create(ahwndParent, apstrName, adwStyle, adwExStyle, arc.left, arc.top, arc.right - arc.left, arc.bottom - arc.top, ahMenu, hInstance);
}

HWND CWinWnd::Create(HWND ahwndParent, LPCTSTR apstrName, DWORD adwStyle, DWORD adwExStyle, int ax, int ay, int acx, int acy, HMENU ahMenu, HINSTANCE ahInstance)
{
if (GetWinClassName() && RegWinClass(ahInstance))
{
m_hWnd = ::CreateWindowEx(adwExStyle, GetWinClassName(), apstrName, adwStyle, ax, ay, acx, acy, ahwndParent, ahMenu, ahInstance, this);
ASSERT(m_hWnd!=NULL);
return m_hWnd;
}
return NULL;
}

void CWinWnd::ShowWindow(BOOL bShow /*= true*/, BOOL bTakeFocus /*= false*/)
{
ASSERT(::IsWindow(m_hWnd));
if( !::IsWindow(m_hWnd) ) return;
::ShowWindow(m_hWnd, bShow ? (bTakeFocus ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE) : SW_HIDE);
}

// 加载初始控件
void CWinWnd::SetWndInfo(HINSTANCE ahInstance, ULong aulStyle,ULong aulStyleEx, int aiXVertex, int aiYVertex, int aiWeigth, int aiHeigth, HMENU	ahMenu)
{
m_ulStyle	= aulStyle;
m_ulStyleEx = aulStyleEx;
m_iXVertex	= aiXVertex;
m_iYVertex	= aiYVertex;
m_iWeigth	= aiWeigth;
m_iHeigth	= aiHeigth;
m_hMenu		= ahMenu;
m_hInstance = ahInstance;
}

// 设置注册类名称
void CWinWnd::SetWinClassName(TCHAR* apClassName)
{
if (!apClassName)
return;

#ifdef UNICODE
memcpy(m_lszRegClassName, apClassName, sizeof(TCHAR)*wcslen(apClassName));
#else
memcpy(m_lszRegClassName, apClassName, strlen(apClassName));
#endif
}

// 获得注册类名称
LPCTSTR CWinWnd::GetWinClassName(void) const
{
return m_lszRegClassName;
}

// 设置窗口名称
void CWinWnd::SetWinName(TCHAR* apWndName)
{
if (!apWndName)
return;
#ifdef UNICODE
memcpy(m_lszWndName, apWndName, sizeof(TCHAR)*wcslen(apWndName));
#else
memcpy(m_lszWndName, apWndName, strlen(apWndName));
#endif

}
// 获得Xml文件名称
LPCTSTR CWinWnd::GetWinName(void) const
{
return m_lszWndName;
}

// 设置Xml文件名称
void CWinWnd::SetXmlFile(TCHAR* apXmlFile)
{
if (!apXmlFile)
return;
#ifdef UNICODE
memcpy(m_szXmlFile, apXmlFile, sizeof(TCHAR)*wcslen(apXmlFile));
#else
memcpy(m_szXmlFile, apXmlFile, strlen(apXmlFile));
#endif

}
// 获得窗口名称
LPCTSTR CWinWnd::GetXmlFile(void) const
{
return m_szXmlFile;
}

HWND CWinWnd::Subclass(HWND hWnd)
{
ASSERT(::IsWindow(hWnd));
ASSERT(m_hWnd==NULL);
m_OldWndProc = SubclassWindow(hWnd, __WndProc);
if( m_OldWndProc == NULL ) return NULL;
m_bSubclassed = true;
m_hWnd = hWnd;
return m_hWnd;
}

void CWinWnd::Unsubclass()
{
ASSERT(::IsWindow(m_hWnd));
if( !::IsWindow(m_hWnd) ) return;
if( !m_bSubclassed ) return;
SubclassWindow(m_hWnd, m_OldWndProc);
m_OldWndProc = ::DefWindowProc;
m_bSubclassed = false;
}

UINT CWinWnd::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( msg.message == WM_CLOSE && msg.hwnd == m_hWnd )
{
nRet = msg.wParam;
::EnableWindow(hWndParent, TRUE);
::SetFocus(hWndParent);
}
//if( !CPaintManagerUI::TranslateMessage(&msg) )
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
if( msg.message == WM_QUIT ) break;
}
::EnableWindow(hWndParent, TRUE);
::SetFocus(hWndParent);
if( msg.message == WM_QUIT ) ::PostQuitMessage(msg.wParam);
return nRet;
}

void CWinWnd::Close(UINT nRet)
{
ASSERT(::IsWindow(m_hWnd));
if( !::IsWindow(m_hWnd) ) return;
::PostMessage(m_hWnd, WM_CLOSE, (WPARAM)nRet, 0L);
}

void CWinWnd::CenterWindow()
{
ASSERT(::IsWindow(m_hWnd));
ASSERT((GetWindowStyle(m_hWnd)&WS_CHILD)==0);
RECT rcDlg = { 0 };
::GetClientRect(m_hWnd, &rcDlg);
RECT rcArea = { 0 };
RECT rcCenter = { 0 };
HWND hWndParent = ::GetParent(m_hWnd);
HWND hWndCenter = ::GetWindowOwner(m_hWnd);
::SystemParametersInfo(SPI_GETWORKAREA, NULL, &rcArea, NULL);
if( hWndCenter == NULL ) rcCenter = rcArea; else ::GetClientRect(hWndCenter, &rcCenter);

int DlgWidth = rcDlg.right - rcDlg.left;
int DlgHeight = rcDlg.bottom - rcDlg.top;

// Find dialog's upper left based on rcCenter
int xLeft = (rcCenter.left + rcCenter.right) / 2 - DlgWidth / 2;
int yTop = (rcCenter.top + rcCenter.bottom) / 2 - DlgHeight / 2;

// The dialog is outside the screen, move it inside
if( xLeft < rcArea.left ) xLeft = rcArea.left;
else if( xLeft + DlgWidth > rcArea.right ) xLeft = rcArea.right - DlgWidth;
if( yTop < rcArea.top ) yTop = rcArea.top;
else if( yTop + DlgHeight > rcArea.bottom ) yTop = rcArea.bottom - DlgHeight;
::SetWindowPos(m_hWnd, NULL, xLeft, yTop, -1, -1, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}

void CWinWnd::SetIcon(UINT nRes)
{
HICON hIcon = (HICON)::LoadImage(m_hInstance, MAKEINTRESOURCE(nRes), IMAGE_ICON, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR);
ASSERT(hIcon);
::SendMessage(m_hWnd, WM_SETICON, (WPARAM) TRUE, (LPARAM) hIcon);
hIcon = (HICON)::LoadImage(m_hInstance, MAKEINTRESOURCE(nRes), IMAGE_ICON, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
ASSERT(hIcon);
::SendMessage(m_hWnd, WM_SETICON, (WPARAM) FALSE, (LPARAM) hIcon);
}


窗体控件构建:CUIBuilder 解析配置文件,构建出窗口上的个个控件窗口(类似于MFC的 Dialog)

头文件:

class CUIBuilder : public CWinWnd
{
public:
CUIBuilder(void);
virtual ~CUIBuilder(void);

public:
BOOL InitUIBuilder( TCHAR*	apClass, TCHAR* apZipPack, TCHAR* apXmlFile, TCHAR* apWndName, HWND ahwndParent, DWORD	adwStyle,
DWORD	adwExStyle, int	ax, int	ay, int	acx, int	acy,
HMENU	ahMenu, HINSTANCE ahInstance);

BOOL DoModule(void);
private:
CUIBaseCtrl* LoadCtrls(TCHAR* apXmlFileName);
LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);

};


实现文件:

#include "StdAfx.h"
#include "UIBuilder.h"

CUIBuilder::CUIBuilder(void)
{
}

CUIBuilder::~CUIBuilder(void)
{
}

CUIBaseCtrl* CUIBuilder::LoadCtrls(TCHAR* apXmlFileName)
{
// 范例代码 这里在窗体上创建了三个逻辑子窗口

//【区域控件】
CUIBaseCtrl* lAreaCtrl = new CUIAreaCtrl(m_pUICache, m_hWnd);
RECT loRect;
::GetClientRect(m_hWnd, &loRect);
lAreaCtrl->SetRect(loRect);
lAreaCtrl->SetBkColor(0x01FFFFFF);
lAreaCtrl->SetCtrlID(1);

//【子按钮控件】
CUIBaseCtrl* lpCtrl = new CUIButton(m_pUICache, m_hWnd);
lpCtrl->SetRect(0,0, 500, 500);
lpCtrl->SetBkColor(0x02FFFFFF);
lpCtrl->SetBkImage(_T("file=\"SysBk.png\"  source=\"0,0,0,0\"  corner=\"10,10,10,10\""));
lpCtrl->SetCtrlID(2);
lAreaCtrl->AddChildCtrl(lpCtrl);

//【嵌套子按钮控件】
CUIBaseCtrl* lpCtrlBt = new CUIButton(m_pUICache, m_hWnd);
lpCtrlBt->SetRect(10,10, 200, 200);
lpCtrlBt->SetBkColor(0x02FFFFFF);
lpCtrlBt->SetCtrlID(3);
lpCtrl->AddChildCtrl(lpCtrlBt);

return lAreaCtrl;
}

LRESULT CUIBuilder::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT lRes = 0;
BOOL bHandled = FALSE;

if( bHandled )
return lRes;
if(!m_oMsgMgr.MessageHandler(uMsg, wParam, lParam, lRes) )
return lRes;
return CWinWnd::HandleMessage(uMsg, wParam, lParam);
}

BOOL CUIBuilder::InitUIBuilder( TCHAR*	apClass, TCHAR* apZipPack,TCHAR* apXmlFile, TCHAR* apWndName, HWND ahwndParent,  DWORD	adwStyle,
DWORD	adwExStyle, int	ax, int	ay, int	acx, int	acy,
HMENU	ahMenu, HINSTANCE ahInstance)
{
// 设置资产类名称
SetWinClassName(apClass);
// 设置窗口名称
SetWinName(apWndName);
// 设置界面配置文件名称
SetXmlFile(apXmlFile);
// 设置窗口信息大小
SetWndInfo(ahInstance, adwStyle, adwExStyle, ax, ay, acx, acy,ahMenu);
// 设置资源文件压缩包路径
if (m_pUICache) m_pUICache->SetResPackName(apZipPack);
return TRUE;
}

BOOL CUIBuilder::DoModule(void)
{
// 创建窗口
if (!Create(NULL, m_lszWndName, m_ulStyle, m_ulStyleEx , m_iXVertex, m_iYVertex, m_iWeigth, m_iHeigth, m_hMenu, m_hInstance))
return FALSE;
// 加载控件配置文件创建控件
m_pRootCtrl = LoadCtrls(m_szXmlFile);
if (!m_pRootCtrl)
return FALSE;
m_oMsgMgr.InitMsgMgr(m_hWnd, m_pRootCtrl);
ShowWindow(TRUE, FALSE);

CMSGMgr::MSGLoop();
return TRUE;
}


附窗体构建后的图:



后续继续补充 消息循环映射处理, 控件构建,渲染等内容。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: