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