duilib是一個windows下的皮膚庫,用win32寫的。。。
先看個效果圖吧:
這個圖片里有源代碼,右鍵保存下圖標,把后綴改為zip,即可。由於skin目錄下的圖片不便上傳,需要自己加入合適的圖片。
要使用duilib庫,必須先把庫導入,代碼如下:
1 #include "xxx\UIlib.h" //xxx為UIlib.h的路徑 2 using namespace Duilib; //Duilib為庫自定義的名字空間 3 4 #ifdef _DEBUG 5 #ifdef _UNICODE 6 #pragma comment(lib, "xxx\Duilib_ud.lib") 7 #else 8 #pragma comment(lib, "xxx\Duilib_d.lib") 9 #endif 10 #else 11 #ifdef _UNICODE 12 #progma comment(lib, "xxx\Duilib_u.lib") 13 #else 14 #progma comment(lib, "xxx\Duilib.lib") 15 #endif
使用duilib庫的程序和win32程序一樣也是從WinMain開始的。在WinMain函數中,一般是這樣做的:
1 CPaintManagerUI::SetInstance(hInstance);//將程序實例與皮膚繪制管理器掛鈎 2 CPaintMamagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath() + TEXT("skin"));//設置皮膚庫的資源路徑,資源有圖片、xml文件等 3 CPaintManagerUI::SetResourceZip(/*路徑*/);//皮膚庫支持壓縮文件,這里指定壓縮文件路徑 4 //new一個類,這個類繼承自CWindowWnd類 5 //調用類的Create函數創建窗口,這里會發送WM_CREATE消息,而這個類一般會在HandleMessage函數中處理WM_CREATE消息 6 //創建完窗口后,可以調用該類的SetIcon(IDI_HW)函數來設置任務欄上顯示的圖標 7 //然后調用CPaintManagerUI::MessageLoop(),進入消息循環
在duilib中每個窗口均要定義一個CPaintManagerUI成員對象用來管理整個窗口的繪制。
duilib中的窗口均繼承自CWindowWnd類,在CWindowWnd類中有虛函數HandleMessage來處理Windows消息(如WM_CREATE、WM_SIZE等)。另外,如果你的窗口想要響應鼠標的點擊、編輯框內容改變等消息的話,可以把你的窗口類繼承INotify接口,這樣你的窗口上的一個按鈕被點擊了,可以在繼承自INotify接口的Notify函數中進行處理。
在自己定義的窗口類中一般這樣來處理HandleMessage:
1 LRESULT CHelloWorld::HandleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam ) 2 { 3 LRESULT lRes = 0;//返回值 4 BOOL bHandled = TRUE;//是否被處理了 5 switch (uMsg) 6 { 7 case WM_CREATE: 8 lRes = OnCreate(uMsg ,wParam, lParam, bHandled); 9 break; 10 default: 11 bHandled = FALSE; break; 12 } 13 14 if (bHandled) return lRes; 15 if (m_pm.MessageHandler(uMsg, wParam, lParam, lRes) != 0)//沒有處理,這傳送給窗口繪制管理器處理,Notify函數將會在這里的m_pm.MessageHandler函數中被調用 16 return lRes; 17 return CWindowWnd::HandleMessage(uMsg, wParam, lParam);//都不處理則有CWindowWnd處理 18 }
INotifyUI接口的Notify()由CPaintManagerUI::MessageHandler調用。繼承INotifyUI接口的類對象會被加入到CPaintManagerUI的m_aNotifiers數組中,而要加入m_aNotifiers數組一般由窗口類自己在OnCreate函數調用CPaintManagerUI的靜態方法AddNotifier將自己加入到m_aNotifiers中。
而在自己的窗口類的OnCreate函數中,通常調用m_pm.Init(m_hWnd)來把自己的窗口句柄與窗口繪制管理器掛接在一起,即用於向CPaintManagerUI提供窗口句柄及窗口上下文句柄。
1 LRESULT CHelloWorld::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2 { 3 m_pm.Init(m_hWnd); // 把自己的窗口句柄與窗口繪制管理器掛接在一起 4 CDialogBuilder builder; 5 CControlUI* pRoot = builder.Create(TEXT("HelloWorld.xml"), (UINT)0, NULL, &m_pm); // 根據xml中的配置創建控件 6 ASSERT(pRoot && "Failure to parse XML"); 7 m_pm.AttachDialog(pRoot); // 把這些控件繪制到本窗口上 8 m_pm.AddNotifier(this); // 把自己加入到CPaintManagerUI的m_aNotifiers數組中,用於處理Notify函數 9 Init(); 10 return 0; 11 12 }
以上就是關於duilib程序的一個建立過程。
貼代碼先:
1 // stdafx.h : 標准系統包含文件的包含文件, 2 // 或是經常使用但不常更改的 3 // 特定於項目的包含文件 4 // 5 6 #pragma once 7 8 #define WIN32_LEAN_AND_MEAN // 從 Windows 頭中排除極少使用的資料 9 // Windows 頭文件: 10 #include <windows.h> 11 #include <objbase.h> 12 13 // TODO: 在此處引用程序需要的其他頭文件 14 #include "..\..\DuiLib\UIlib.h" 15 16 using namespace DuiLib; 17 18 #ifdef _DEBUG 19 # ifdef _UNICODE 20 # pragma comment(lib, "..\\..\\bin\\DuiLib_ud.lib") 21 # else 22 # pragma comment(lib, "..\\..\\bin\\DuiLib_d.lib") 23 # endif 24 #else 25 # ifdef _UNICODE 26 # pragma comment(lib, "..\\..\\bin\\DuiLib_u.lib") 27 # else 28 # pragma comment(lib, "..\\..\\bin\\DuiLib.lib") 29 # endif 30 #endif
1 // stdafx.cpp : 只包括標准包含文件的源文件 2 // HelloWorld.pch 將作為預編譯頭 3 // stdafx.obj 將包含預編譯類型信息 4 5 #include "stdafx.h" 6 7 // TODO: 在 STDAFX.H 中 8 // 引用任何所需的附加頭文件,而不是在此文件中引用
1 // HelloWorld.h 2 #pragma once 3 4 class CHelloWorld: public CWindowWnd, public INotifyUI // 繼承自CWindowWnd和INotifyUI 5 { 6 ////////////////////////////////////////////////////////////////////////// 7 // 構造函數及自定義函數 8 public: 9 CHelloWorld(); 10 void Init(); // 界面控件一些初始化、比如某個按鈕最開始是禁用狀態就應該在這個時候處理... 11 void OnOK(); // 點擊OK按鈕的處理 12 void OnClose(); // 點擊Close按鈕的處理 13 14 // WM_CREATE消息的處理 15 LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); 16 // WM_NCHITTEST消息的處理 17 LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); 18 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); 19 LRESULT OnNcActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); 20 LRESULT OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); 21 LRESULT OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); 22 LRESULT OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); 23 24 ////////////////////////////////////////////////////////////////////////// 25 // 繼承自CWindowWnd類 26 public: 27 LPCTSTR GetWindowClassName() const ; // 純虛函數,必須有實現 28 UINT GetClassStyle() const; 29 void OnFinalMessage(HWND /*hWnd*/); // 窗口接收到最后一條消息的處理 30 LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam); // 消息響應函數 31 32 ////////////////////////////////////////////////////////////////////////// 33 34 // 繼承自INotifyUI接口 35 public: 36 void Notify(TNotifyUI& msg); 37 38 ////////////////////////////////////////////////////////////////////////// 39 40 // 成員變量 41 ////////////////////////////////////////////////////////////////////////// 42 private: 43 CButtonUI* m_pBtnOK; // 按鈕控件 44 CButtonUI* m_pBtnClose;// 按鈕控件 45 46 CPaintManagerUI m_pm; // 窗口繪制器 47 };
1 // HelloWorld.cpp : 定義應用程序的入口點。 2 // 3 4 #include "stdafx.h" 5 #include "HelloWorld.h" 6 #include "resource.h" 7 8 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int nCmdShow) 9 { 10 CPaintManagerUI::SetInstance(hInstance); // 將程序實例與皮膚繪制管理器掛鈎 11 // 設置皮膚庫的資源路徑,資源有圖片、xml文件等 12 CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath() + TEXT("skin")); 13 14 HRESULT Hr = ::CoInitialize(NULL); 15 if( FAILED(Hr) ) return 0; 16 17 CHelloWorld* pHW = new CHelloWorld(); 18 if (pHW == NULL) 19 return 0; 20 pHW->Create(NULL, TEXT("Hello World"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE | WS_EX_APPWINDOW); 21 pHW->SetIcon(IDI_HW); 22 pHW->CenterWindow(); 23 pHW->ShowWindow(); 24 CPaintManagerUI::MessageLoop(); 25 26 ::CoUninitialize(); 27 return 0; 28 } 29 30 CHelloWorld::CHelloWorld() 31 : m_pBtnOK(NULL) 32 , m_pBtnClose(NULL) 33 { 34 35 } 36 37 void CHelloWorld::Init() // 本例中此函數其實沒有做任何事情 38 { 39 m_pBtnOK = static_cast<CButtonUI *>(m_pm.FindControl(TEXT("OK"))); 40 if (m_pBtnOK == NULL) 41 return; 42 // m_pBtnOK->OnNotify += MakeDelegate(this, &CHelloWorld::OnOK); 43 // MakeDelegate的實現感覺很強大,這樣也可以實現把OK按鈕的時間轉接到OnOK來處理 44 45 m_pBtnClose = static_cast<CButtonUI *>(m_pm.FindControl(TEXT("Close"))); 46 if (m_pBtnClose == NULL) 47 return; 48 //m_pBtnClose->OnNotify += MakeDelegate(this, &CHelloWorld::OnClose); 49 } 50 51 void CHelloWorld::OnOK() 52 { 53 Close(); // CWindowWnd繼承來的函數Close,是關閉自己 54 } 55 56 void CHelloWorld::OnClose() 57 { 58 Close(); 59 } 60 61 LPCTSTR CHelloWorld::GetWindowClassName() const 62 { 63 return TEXT("HelloWorld"); 64 } 65 66 UINT CHelloWorld::GetClassStyle() const 67 { 68 return UI_CLASSSTYLE_FRAME | CS_DBLCLKS; 69 } 70 71 void CHelloWorld::OnFinalMessage( HWND /*hWnd*/ ) 72 { 73 delete this; 74 } 75 76 LRESULT CHelloWorld::HandleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam ) 77 { 78 LRESULT lRes = 0; 79 BOOL bHandled = TRUE; 80 switch (uMsg) 81 { 82 case WM_CREATE: 83 lRes = OnCreate(uMsg ,wParam, lParam, bHandled); 84 break; 85 86 case WM_DESTROY: 87 ::PostQuitMessage(0); 88 bHandled = FALSE; 89 break; 90 91 case WM_NCHITTEST: 92 lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); 93 break; 94 95 case WM_KEYDOWN: 96 if (wParam == VK_ESCAPE) 97 { 98 OnClose(); 99 } 100 break; 101 102 case WM_SIZE: 103 lRes = OnSize(uMsg, wParam, lParam, bHandled); 104 break; 105 106 case WM_NCACTIVATE: 107 lRes = OnNcActivate(uMsg, wParam, lParam, bHandled); 108 break; 109 110 case WM_GETMINMAXINFO: 111 lRes = true; 112 OnGetMinMaxInfo(uMsg, wParam, lParam, bHandled); 113 break; 114 115 case WM_SYSCOMMAND: 116 lRes = OnSysCommand(uMsg, wParam, lParam, bHandled); 117 break; 118 119 case WM_NCCALCSIZE: 120 lRes = OnNcCalcSize(uMsg, wParam, lParam, bHandled); 121 break; 122 123 default: 124 bHandled = FALSE; break; 125 } 126 127 if (bHandled) return lRes; 128 if (m_pm.MessageHandler(uMsg, wParam, lParam, lRes) != 0) 129 return lRes; 130 return CWindowWnd::HandleMessage(uMsg, wParam, lParam); 131 } 132 133 LRESULT CHelloWorld::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 134 { 135 //LONG styleValue = ::GetWindowLong(*this, GWL_STYLE); 136 //styleValue &= ~WS_CAPTION; 137 //::SetWindowLong(*this, GWL_STYLE, styleValue | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); 138 //RECT rcClient; 139 //::GetClientRect(*this, &rcClient); 140 //::SetWindowPos(*this, NULL, rcClient.left, rcClient.top, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, SWP_FRAMECHANGED); 141 142 m_pm.Init(m_hWnd); // 把自己的窗口句柄與窗口繪制管理器掛接在一起 143 CDialogBuilder builder; 144 // 根據xml的配置來創建控件 145 CControlUI* pRoot = builder.Create(TEXT("HelloWorld.xml"), (UINT)0, NULL, &m_pm); 146 ASSERT(pRoot && "Failure to parse XML"); 147 m_pm.AttachDialog(pRoot); // 把上面的控件繪制到本窗口上,之前有把m_hWnd傳給m_pm 148 m_pm.AddNotifier(this); // 把自己加入到CPaintManagerUI的m_aNotifiers數組中,用於處理Notify函數 149 Init(); 150 return 0; 151 152 } 153 154 LRESULT CHelloWorld::OnSize( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) 155 { 156 SIZE szRoundCorner = m_pm.GetRoundCorner(); // GetRoundCorner用來獲取xml中的Window標簽中roundcorner屬性值,該值指示圓角的長寬 157 if( !::IsIconic(*this) && (szRoundCorner.cx != 0 || szRoundCorner.cy != 0) ) { 158 CRect rcWnd; 159 ::GetWindowRect(*this, &rcWnd); 160 rcWnd.Offset(-rcWnd.left, -rcWnd.top); // rcWnd.right就成為了窗口的寬度了 161 rcWnd.right++; rcWnd.bottom++; 162 HRGN hRgn = ::CreateRoundRectRgn(rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom, szRoundCorner.cx, szRoundCorner.cy); 163 ::SetWindowRgn(*this, hRgn, TRUE); // 窗口圓角化處理 164 ::DeleteObject(hRgn); 165 } 166 167 bHandled = FALSE; 168 return 0; 169 } 170 171 LRESULT CHelloWorld::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 172 { 173 POINT pt; pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); 174 ::ScreenToClient(*this, &pt); 175 176 RECT rcClient; 177 ::GetClientRect(*this, &rcClient); 178 179 if( !::IsZoomed(*this) ) { 180 RECT rcSizeBox = m_pm.GetSizeBox(); // GetSizeBox用來獲取xml中Window標簽的sizebox屬性,該屬性指示你的鼠標移動到窗口邊框多少個像素會變成指示符(這個指示符表示可以改變窗口大小的指示符) 181 if( pt.y < rcClient.top + rcSizeBox.top ) { 182 if( pt.x < rcClient.left + rcSizeBox.left ) return HTTOPLEFT; 183 if( pt.x > rcClient.right - rcSizeBox.right ) return HTTOPRIGHT; 184 return HTTOP; 185 } 186 else if( pt.y > rcClient.bottom - rcSizeBox.bottom ) { 187 if( pt.x < rcClient.left + rcSizeBox.left ) return HTBOTTOMLEFT; 188 if( pt.x > rcClient.right - rcSizeBox.right ) return HTBOTTOMRIGHT; 189 return HTBOTTOM; 190 } 191 if( pt.x < rcClient.left + rcSizeBox.left ) return HTLEFT; 192 if( pt.x > rcClient.right - rcSizeBox.right ) return HTRIGHT; 193 } 194 195 RECT rcCaption = m_pm.GetCaptionRect(); // GetCaptionRect用來獲取xml中Window標簽的caption屬性,該屬性指示標題欄的大小 196 if( pt.x >= rcClient.left + rcCaption.left && pt.x < rcClient.right - rcCaption.right && pt.y >= rcCaption.top && pt.y < rcCaption.bottom ) { 197 CControlUI* pControl = static_cast<CControlUI*>(m_pm.FindControl(pt)); 198 if( pControl && _tcsicmp(pControl->GetClass(), _T("ButtonUI")) != 0 && _tcsicmp(pControl->GetClass(), _T("OptionUI")) != 0) 199 return HTCAPTION; 200 } 201 202 return HTCLIENT; 203 } 204 205 void CHelloWorld::Notify( TNotifyUI& msg ) 206 { 207 if (msg.sType == TEXT("click")) // click事件 208 { 209 if (msg.pSender->GetName() == TEXT("OK")) 210 OnOK(); 211 if (msg.pSender->GetName() == TEXT("Close")) 212 OnClose(); 213 } 214 else if (msg.sType == TEXT("windowinit")) 215 { 216 } 217 } 218 219 LRESULT CHelloWorld::OnNcActivate( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) 220 { 221 if( ::IsIconic(*this) ) bHandled = FALSE; 222 return (wParam == 0) ? TRUE : FALSE; 223 } 224 225 LRESULT CHelloWorld::OnGetMinMaxInfo( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) 226 { 227 MONITORINFO oMonitor = {}; 228 oMonitor.cbSize = sizeof(oMonitor); 229 ::GetMonitorInfo(::MonitorFromWindow(*this, MONITOR_DEFAULTTOPRIMARY), &oMonitor); 230 CRect rcWork = oMonitor.rcWork; 231 rcWork.Offset(-rcWork.left, -rcWork.top); 232 233 LPMINMAXINFO lpMMI = (LPMINMAXINFO) lParam; 234 lpMMI->ptMaxPosition.x = rcWork.left; 235 lpMMI->ptMaxPosition.y = rcWork.top; 236 lpMMI->ptMaxSize.x = rcWork.right; 237 lpMMI->ptMaxSize.y = rcWork.bottom; 238 239 bHandled = FALSE; 240 return 0; 241 } 242 243 LRESULT CHelloWorld::OnSysCommand( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) 244 { 245 if (wParam == SC_CLOSE) 246 { 247 bHandled = TRUE; 248 SendMessage(WM_CLOSE); 249 return 0; 250 } 251 #if defined(WIN32) && !defined(UNDER_CE) 252 BOOL bZoomed = ::IsZoomed(*this); 253 LRESULT lRes = CWindowWnd::HandleMessage(uMsg, wParam, lParam); 254 if( ::IsZoomed(*this) != bZoomed ) 255 { 256 } 257 #else 258 LRESULT lRes = CWindowWnd::HandleMessage(uMsg, wParam, lParam); 259 #endif 260 return lRes; 261 } 262 263 LRESULT CHelloWorld::OnNcCalcSize( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) 264 { 265 return 0; 266 // wParam為TRUE時,返回0將會使窗口的大小變為客戶區的大小,也就是說這將把窗口的標題欄、窗口邊框移除,只顯示客戶區 267 }
1 // xml皮膚配置文件 2 <?xml version="1.0" encoding="utf-8" standalone="yes" ?> 3 <Window size="400,250" caption="0,0,0,30" roundcorner="6,6" sizebox="4,4,4,4" mininfo="100,50" maxinfo="500,300"> 4 <VerticalLayout bkcolor="#FF000000"> 5 <HorizontalLayout width="400" height="30" bkimage="file='top_bg.png' corner='5,5,5,5'"> 6 <HorizontalLayout widht="80"> 7 <Button name="OK" text="OK" align="center" width="80" height="30" textcolor="#FFC8C8C8" disabletextcolor="#FFA7A6AA" normalimage="file='BtnOK.png' source='0,0,80,30'" hotimage="file='BtnOK.png' source='80,0,160,30'" pushedimage="file='BtnOK.png' source='160,0,240,30'" disabledimage="file='BtnOK.png' source='240,0,320,30'" /> 8 </HorizontalLayout> 9 <HorizontalLayout width="240"> 10 <Label name="caption" text="Hello World" textcolor="#FFFFFFFF" align="center" /> 11 </HorizontalLayout> 12 <HorizontalLayout widht="80"> 13 <Button name="Close" text="Close" align="center" width="79" height="30" textcolor="#FFC8C8C8" disabletextcolor="#FFA7A6AA" normalimage="file='BtnClose.png' source='0,0,79,30'" hotimage="file='BtnClose.png' source='80,0,158,30'" pushedimage="file='BtnClose.png' source='159,0,237,30'" disabledimage="file='BtnClose.png' source='238,0,316,30'" /> 14 </HorizontalLayout> 15 </HorizontalLayout> 16 <VerticalLayout bkimage="file='MBbottombg.png' corner='6,6,6,6'"> 17 18 </VerticalLayout> 19 </VerticalLayout> 20 </Window>
其他:
1.開始寫完程序運行后發現任務欄上沒有圖標,原來可以用SetIcon函數來設置,SetIcon函數的參數是一個資源ID(UINT類型),可以自己繪制一個圖標或者導入一個,然后將該圖標的id傳入即可,還是比較方便的。注意的是SetIcon不需要使用MAKEINTRESOURCE來轉換,在SetIcon函數內調用了MAKEINTRESOURCE。
2.在用窗口類的Create函數時,指定UI_WNDSTYLE_FRAME為第三個參數時,窗口可以雙擊最大化,而使用UI_WNDSTYLE_DIALOG時無法最大化。原來
1 #define UI_WNDSTYLE_FRAME (WS_VISIBLE | WS_OVERLAPPEDWINDOW) 2 #define UI_WNDSTYLE_CHILD (WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN) 3 #define UI_WNDSTYLE_DIALOG (WS_VISIBLE | WS_POPUPWINDOW | WS_CAPTION | WS_DLGFRAME | WS_CLIPSIBLINGS | WS_CLIPCHILDREN)
WS_OVERLAPPEDWINDOW默認帶有WM_MAXIMIZEBOX屬性,固默認可以雙擊最大化。WS_POPUPWINDOW默認有WS_BORDER,WS_POPUP和WS_SYSMENU屬性,沒有WM_MAXIMIZEBOX屬性,固POPUPWINDOW默認無法雙擊最大化。
3.WM_NCCALCSIZE消息的處理,MSDN中有這么一段描述
When wParam is TRUE, simply returning 0 without processing the NCCALCSIZE_PARAMS rectangles will cause the client area to resize to the size of the window, including the window frame. This will remove the window frame and caption items from your window, leaving only the client area displayed.
也就是說這個消息處理時返回0,則窗口將會沒有標題欄和外邊框,只有客戶區了。
4.WM_NCHITTEST消息的處理,可以返回HTTOPLEFT(窗口的左上角,鼠標變為可調邊框標識)、HTTOPRIGHT等。返回HTCAPTION標識擊中為標題欄,返回HTCLIENT標識擊中為客戶區。
5.按鍵消息的處理:可繼承IMessageFilterUI,該接口有MessageHandler純虛函數,自己要實現對按鍵的處理;在OnCreate中把自己加入到繪制管理器對象的m_aPreMessageFilters預處理消息數組中。這樣在繪制管理器的MessageLoop()中將調用TranslateMessage按鍵處理,在TranslateMessage又將調用PreMessageHandler,然后PreMessageHandler中又將調用MessageHandler函數(即那個需要處理按鍵消息的窗口類的函數)
6.foreimage可以在按鈕的背景上加入前景圖片;控件的float設為true時,改變窗口大小,控件的顯示會有問題,只能顯示控件的一部分,解決辦法是使用布局來控制控件位置,不用設置控件位置;relativePos要與float="true"同用,可調節百分比;pos屬性也要與float="true"同用才可調節控件位置;皮膚科刷新有問題,必須依賴於背景顏色;