在vs2008里,新建一个win32的程序空项目。建立stdafx.h和stdafx.cpp文件,代码如下:
stdafx.h
#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) #define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_ #pragma once #define WIN32_LEAN_AND_MEAN #define _CRT_SECURE_NO_DEPRECATE #include <windows.h> #include <objbase.h> #include "..\DuiLib\UIlib.h" using namespace DuiLib; #ifdef _DEBUG # ifdef _UNICODE # pragma comment(lib, "..\\bin\\DuiLib_ud.lib") # else # pragma comment(lib, "..\\bin\\DuiLib_d.lib") # endif #else # ifdef _UNICODE # pragma comment(lib, "..\\bin\\DuiLib_u.lib") # else # pragma comment(lib, "..\\bin\\DuiLib.lib") # endif #endif //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
stdafx.cpp
// stdafx.cpp : source file that includes just the standard includes // App.pch will be the pre-compiled header // stdafx.obj will contain the pre-compiled type information #include "stdafx.h" #if defined _M_IX86 #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") #elif defined _M_IA64 #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") #elif defined _M_X64 #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") #else #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") #endif
再建立一个cpp用来写主程序。
最简单的窗口中系统的按钮,这些还有一些系统命令的处理,因此得重写CWindowWnd里面的函数:
class CFrameWindowWnd : public CWindowWnd, public INotifyUI { public: CFrameWindowWnd() { }; LPCTSTR GetWindowClassName() const { return _T("UIMainFrame"); }; UINT GetClassStyle() const { return CS_DBLCLKS; }; void OnFinalMessage(HWND /*hWnd*/) { delete this; }; void Init() { m_pCloseBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("closebtn"))); m_pMaxBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("maxbtn"))); m_pRestoreBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("restorebtn"))); m_pMinBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("minbtn"))); } void OnPrepare() { } void Notify(TNotifyUI& msg) { if( msg.sType == _T("windowinit") ) OnPrepare(); else if( msg.sType == _T("click") ) { if( msg.pSender == m_pCloseBtn ) { PostQuitMessage(0); return; } else if( msg.pSender == m_pMinBtn ) { SendMessage(WM_SYSCOMMAND, SC_MINIMIZE, 0); return; } else if( msg.pSender == m_pMaxBtn ) { SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE, 0); return; } else if( msg.pSender == m_pRestoreBtn ) { SendMessage(WM_SYSCOMMAND, SC_RESTORE, 0); return; } } } LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { LONG styleValue = ::GetWindowLong(*this, GWL_STYLE); styleValue &= ~WS_CAPTION; ::SetWindowLong(*this, GWL_STYLE, styleValue | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); m_pm.Init(m_hWnd); CDialogBuilder builder; CControlUI* pRoot = builder.Create(_T("myTest.xml"), (UINT)0, 0, &m_pm); ASSERT(pRoot && "Failed to parse XML"); m_pm.AttachDialog(pRoot); m_pm.AddNotifier(this); Init(); return 0; } LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { bHandled = FALSE; return 0; } LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { ::PostQuitMessage(0L); bHandled = FALSE; return 0; } LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { SIZE szRoundCorner = m_pm.GetRoundCorner(); if( !::IsIconic(*this) && (szRoundCorner.cx != 0 || szRoundCorner.cy != 0) ) { CRect rcWnd; ::GetWindowRect(*this, &rcWnd); rcWnd.Offset(-rcWnd.left, -rcWnd.top); rcWnd.right++; rcWnd.bottom++; HRGN hRgn = ::CreateRoundRectRgn(rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom, szRoundCorner.cx, szRoundCorner.cy); ::SetWindowRgn(*this, hRgn, TRUE); ::DeleteObject(hRgn); } bHandled = FALSE; return 0; } LRESULT OnNcActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if( ::IsIconic(*this) ) bHandled = FALSE; return (wParam == 0) ? TRUE : FALSE; } LRESULT OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return 0; } LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return 0; } LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { POINT pt; pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); ::ScreenToClient(*this, &pt); RECT rcClient; ::GetClientRect(*this, &rcClient); RECT rcCaption = m_pm.GetCaptionRect(); if( pt.x >= rcClient.left + rcCaption.left && pt.x < rcClient.right - rcCaption.right \ && pt.y >= rcCaption.top && pt.y < rcCaption.bottom ) { CControlUI* pControl = static_cast<CControlUI*>(m_pm.FindControl(pt)); if( pControl && _tcscmp(pControl->GetClass(), _T("ButtonUI")) != 0 && _tcscmp(pControl->GetClass(), _T("OptionUI")) != 0 && _tcscmp(pControl->GetClass(), _T("TextUI")) != 0 ) return HTCAPTION; } return HTCLIENT; } LRESULT OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { // 有时会在收到WM_NCDESTROY后收到wParam为SC_CLOSE的WM_SYSCOMMAND if( wParam == SC_CLOSE ) { ::PostQuitMessage(0L); bHandled = TRUE; return 0; } BOOL bZoomed = ::IsZoomed(*this); LRESULT lRes = CWindowWnd::HandleMessage(uMsg, wParam, lParam); if( ::IsZoomed(*this) != bZoomed ) { if( !bZoomed ) { CControlUI* pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("maxbtn"))); if( pControl ) pControl->SetVisible(false); pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("restorebtn"))); if( pControl ) pControl->SetVisible(true); } else { CControlUI* pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("maxbtn"))); if( pControl ) pControl->SetVisible(true); pControl = static_cast<CControlUI*>(m_pm.FindControl(_T("restorebtn"))); if( pControl ) pControl->SetVisible(false); } } return lRes; } LRESULT OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { MONITORINFO oMonitor = {}; oMonitor.cbSize = sizeof(oMonitor); ::GetMonitorInfo(::MonitorFromWindow(*this, MONITOR_DEFAULTTOPRIMARY), &oMonitor); CRect rcWork = oMonitor.rcWork; rcWork.Offset(-rcWork.left, -rcWork.top); LPMINMAXINFO lpMMI = (LPMINMAXINFO) lParam; lpMMI->ptMaxPosition.x = rcWork.left; lpMMI->ptMaxPosition.y = rcWork.top; lpMMI->ptMaxSize.x = rcWork.right; lpMMI->ptMaxSize.y = rcWork.bottom; bHandled = FALSE; return 0; } LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lRes = 0; BOOL bHandled = TRUE; switch( uMsg ) { case WM_CREATE: lRes = OnCreate(uMsg, wParam, lParam, bHandled); break; case WM_CLOSE: lRes = OnClose(uMsg, wParam, lParam, bHandled); break; case WM_DESTROY: lRes = OnDestroy(uMsg, wParam, lParam, bHandled); break; case WM_NCACTIVATE: lRes = OnNcActivate(uMsg, wParam, lParam, bHandled); break; case WM_NCCALCSIZE: lRes = OnNcCalcSize(uMsg, wParam, lParam, bHandled); break; case WM_NCPAINT: lRes = OnNcPaint(uMsg, wParam, lParam, bHandled); break; case WM_NCHITTEST: lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); break; case WM_SIZE: lRes = OnSize(uMsg, wParam, lParam, bHandled); break; case WM_GETMINMAXINFO: lRes = OnGetMinMaxInfo(uMsg, wParam, lParam, bHandled); break; case WM_SYSCOMMAND: lRes = OnSysCommand(uMsg, wParam, lParam, bHandled); break; default: bHandled = FALSE; } if( bHandled ) return lRes; if( m_pm.MessageHandler(uMsg, wParam, lParam, lRes) ) return lRes; return CWindowWnd::HandleMessage(uMsg, wParam, lParam); } public: CPaintManagerUI m_pm; private: CButtonUI* m_pCloseBtn; CButtonUI* m_pMaxBtn; CButtonUI* m_pRestoreBtn; CButtonUI* m_pMinBtn; };
接着就可以写winmain函数了
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int nCmdShow) { CPaintManagerUI::SetInstance(hInstance); CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath()); HRESULT Hr = ::CoInitialize(NULL); if( FAILED(Hr) ) return 0; CFrameWindowWnd* pFrame = new CFrameWindowWnd(); if( pFrame == NULL ) return 0; pFrame->Create(NULL, _T("Duilib简单程序"), UI_WNDSTYLE_FRAME, 0L, 0, 0, 800, 572); pFrame->CenterWindow(); pFrame->ShowWindow(true); CPaintManagerUI::MessageLoop(); ::CoUninitialize(); return 0; }
界面的xml文件为:
<?xml version="1.0" encoding="utf-8"?> <Window size="800,572" sizebox="4,4,6,6" roundcorner="5,5" caption="0,0,0,30" mininfo="800,570"> <Font name="宋体" size="13" bold="true" /> <Font name="宋体" size="12" bold="true" /> <Font name="宋体" size="12" /> <Font name="宋体" size="14" bold="true" /> <Font name="宋体" size="22" bold="true" italic="true"/> <Font name="宋体" size="12" /> <Default name="VScrollBar" value="button1normalimage="file='scrollbar.bmp' source='0,90,16,106' mask='#FFFF00FF'" button1hotimage="file='scrollbar.bmp' source='18,90,34,106' mask='#FFFF00FF'" button1pushedimage="file='scrollbar.bmp' source='36,90,52,106' mask='#FFFF00FF'" button1disabledimage="file='scrollbar.bmp' source='54,90,70,106' mask='#FFFF00FF'" button2normalimage="file='scrollbar.bmp' source='0,108,16,124' mask='#FFFF00FF'" button2hotimage="file='scrollbar.bmp' source='18,108,34,124' mask='#FFFF00FF'" button2pushedimage="file='scrollbar.bmp' source='36,108,52,124' mask='#FFFF00FF'" button2disabledimage="file='scrollbar.bmp' source='54,108,70,124' mask='#FFFF00FF'" thumbnormalimage="file='scrollbar.bmp' source='0,126,16,142' corner='2,2,2,2' mask='#FFFF00FF'" thumbhotimage="file='scrollbar.bmp' source='18,126,34,142' corner='2,2,2,2' mask='#FFFF00FF'" thumbpushedimage="file='scrollbar.bmp' source='36,126,52,142' corner='2,2,2,2' mask='#FFFF00FF'" thumbdisabledimage="file='scrollbar.bmp' source='54,126,70,142' corner='2,2,2,2' mask='#FFFF00FF'" railnormalimage="file='scrollbar.bmp' source='0,144,16,160' corner='2,2,2,2' mask='#FFFF00FF'" railhotimage="file='scrollbar.bmp' source='18,144,34,160' corner='2,2,2,2' mask='#FFFF00FF'" railpushedimage="file='scrollbar.bmp' source='36,144,52,160' corner='2,2,2,2' mask='#FFFF00FF'" raildisabledimage="file='scrollbar.bmp' source='54,144,70,160' corner='2,2,2,2' mask='#FFFF00FF'" bknormalimage="file='scrollbar.bmp' source='0,162,16,178' corner='2,2,2,2' mask='#FFFF00FF'" bkhotimage="file='scrollbar.bmp' source='18,162,34,178' corner='2,2,2,2' mask='#FFFF00FF'" bkpushedimage="file='scrollbar.bmp' source='36,162,52,178' corner='2,2,2,2' mask='#FFFF00FF'" bkdisabledimage="file='scrollbar.bmp' source='54,162,70,178' corner='2,2,2,2' mask='#FFFF00FF'" " /> <Default name="HScrollBar" value="button1normalimage="file='scrollbar.bmp' source='0,0,16,16' mask='#FFFF00FF'" button1hotimage="file='scrollbar.bmp' source='18,0,34,16' mask='#FFFF00FF'" button1pushedimage="file='scrollbar.bmp' source='36,0,52,16' mask='#FFFF00FF'" button1disabledimage="file='scrollbar.bmp' source='54,0,70,16' mask='#FFFF00FF'" button2normalimage="file='scrollbar.bmp' source='0,18,16,34' mask='#FFFF00FF'" button2hotimage="file='scrollbar.bmp' source='18,18,34,34' mask='#FFFF00FF'" button2pushedimage="file='scrollbar.bmp' source='36,18,52,34' mask='#FFFF00FF'" button2disabledimage="file='scrollbar.bmp' source='54,18,70,34' mask='#FFFF00FF'" thumbnormalimage="file='scrollbar.bmp' source='0,36,16,52' corner='2,2,2,2' mask='#FFFF00FF'" thumbhotimage="file='scrollbar.bmp' source='18,36,34,52' corner='2,2,2,2' mask='#FFFF00FF'" thumbpushedimage="file='scrollbar.bmp' source='36,36,52,52' corner='2,2,2,2' mask='#FFFF00FF'" thumbdisabledimage="file='scrollbar.bmp' source='54,36,70,52' corner='2,2,2,2' mask='#FFFF00FF'" railnormalimage="file='scrollbar.bmp' source='0,54,16,70' corner='2,2,2,2' mask='#FFFF00FF'" railhotimage="file='scrollbar.bmp' source='18,54,34,70' corner='2,2,2,2' mask='#FFFF00FF'" railpushedimage="file='scrollbar.bmp' source='36,54,52,70' corner='2,2,2,2' mask='#FFFF00FF'" raildisabledimage="file='scrollbar.bmp' source='54,54,70,70' corner='2,2,2,2' mask='#FFFF00FF'" bknormalimage="file='scrollbar.bmp' source='0,72,16,88' corner='2,2,2,2' mask='#FFFF00FF'" bkhotimage="file='scrollbar.bmp' source='18,72,34,88' corner='2,2,2,2' mask='#FFFF00FF'" bkpushedimage="file='scrollbar.bmp' source='36,72,52,88' corner='2,2,2,2' mask='#FFFF00FF'" bkdisabledimage="file='scrollbar.bmp' source='54,72,70,88' corner='2,2,2,2' mask='#FFFF00FF'" " /> <VerticalLayout bkcolor="#FFD1E8F5" bkcolor2="#FFC6E0F1" bordercolor="#FF768D9B" bordersize="1" borderround="5,5" inset="1,0,1,0"> <HorizontalLayout height="24"> <HorizontalLayout> <Container width="22" height="22" bkimage="file='icon.png' source='0,0,16,16' dest='5,4,21,20' " /> <Text text="Duilib简单程序" pos="22, 5, 200, 24" float="true" textcolor="#FF447AA1" font="0" /> </HorizontalLayout> <HorizontalLayout width="188" inset="0,1,0,0"> <Button text="{u}{a}求助{/a}{/u}" showhtml="true"/> <Button text="{u}{a}论坛{/a}{/u}" showhtml="true"/> <Button name="menubtn" maxwidth="26" maxheight="17" normalimage="file='sys_dlg_menu.png' source='52,0,78,17'" hotimage="file='sys_dlg_menu.png' source='26,0,52,17'" pushedimage="file='sys_dlg_menu.png' source='0,0,26,17'"/> <Button name="minbtn" maxwidth="26" maxheight="17" normalimage="file='sys_dlg_min.png' source='52,0,78,17'" hotimage="file='sys_dlg_min.png' source='26,0,52,17'" pushedimage="file='sys_dlg_min.png' source='0,0,26,17'"/> <Button name="maxbtn" maxwidth="26" maxheight="17" normalimage="file='sys_dlg_max.png' source='52,0,78,17'" hotimage="file='sys_dlg_max.png' source='26,0,52,18'" pushedimage="file='sys_dlg_max.png' source='0,0,26,17'"/> <Button name="restorebtn" visible="false" maxwidth="26" maxheight="17" normalimage="file='sys_dlg_restore.png' source='52,0,78,17'" hotimage="file='sys_dlg_restore.png' source='26,0,52,17'" pushedimage="file='sys_dlg_restore.png' source='0,0,26,17'" /> <Button name="closebtn" maxwidth="45" maxheight="17" normalimage="file='sys_dlg_close.png' source='90,0,135,17'" hotimage="file='sys_dlg_close.png' source='45,0,90,17'" pushedimage="file='sys_dlg_close.png' source='0,0,45,17'"/> </HorizontalLayout> </HorizontalLayout> </VerticalLayout> </Window>
这就完成了一个简单的程序框架,已经具备的功能有最小、大化窗口、关闭窗口、还原窗口。窗口的拖动,以及界面的圆角。