客户端
目前客户端的实现,不少大公司采用了较为新潮的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
实现文件:
#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;
}
附窗体构建后的图:
后续继续补充 消息循环映射处理, 控件构建,渲染等内容。