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

客户端

       目前客户端的实现,不少大公司采用了较为新潮的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 

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 


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(lParam);
		pThis = static_cast(lpcs->lpCreateParams);
		
		if (pThis)
		{
			pThis->m_hWnd = hWnd;
			::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast(pThis));
		}
	} 
	else 
	{
		pThis = reinterpret_cast(::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;
}


 

 

附窗体构建后的图:

 

 

 后续继续补充 消息循环映射处理, 控件构建,渲染等内容。

 

你可能感兴趣的:(架构设计)