第一个duilib程序 - 实现HelloWorld详解
duilib是一个windows下的皮肤库,用win32写的。。。
先看个效果图吧:
要使用duilib库,必须先把库导入,代码如下:
1 | #include "xxx\UIlib.h" //xxx为UIlib.h的路径 |
2 | usingnamespaceDuilib; //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 | LRESULTCHelloWorld::HandleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam ) |
2 | { |
3 | LRESULT lRes =0;//返回值 |
4 | BOOL bHandled =TRUE;//是否被处理了 |
5 | switch (uMsg) |
6 | { |
7 | caseWM_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 | returnCWindowWnd::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 | LRESULTCHelloWorld::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 | return0; |
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 | usingnamespaceDuiLib; |
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 | classCHelloWorld:publicCWindowWnd, publicINotifyUI// 继承自CWindowWnd和INotifyUI |
5 | { |
6 | ////////////////////////////////////////////////////////////////////////// |
7 | // 构造函数及自定义函数 |
8 | public: |
9 | CHelloWorld(); |
10 | voidInit(); // 界面控件一些初始化、比如某个按钮最开始是禁用状态就应该在这个时候处理... |
11 | voidOnOK(); // 点击OK按钮的处理 |
12 | voidOnClose(); // 点击Close按钮的处理 |
13 |
|
14 | // WM_CREATE消息的处理 |
15 | LRESULTOnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); |
16 | // WM_NCHITTEST消息的处理 |
17 | LRESULTOnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); |
18 | LRESULTOnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); |
19 | LRESULTOnNcActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); |
20 | LRESULTOnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); |
21 | LRESULTOnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); |
22 | LRESULTOnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); |
23 |
|
24 | ////////////////////////////////////////////////////////////////////////// |
25 | // 继承自CWindowWnd类 |
26 | public: |
27 | LPCTSTRGetWindowClassName() const ; // 纯虚函数,必须有实现 |
28 | UINTGetClassStyle() const; |
29 | voidOnFinalMessage(HWND/*hWnd*/); // 窗口接收到最后一条消息的处理 |
30 | LRESULTHandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam); // 消息响应函数 |
31 |
|
32 | ////////////////////////////////////////////////////////////////////////// |
33 |
|
34 | // 继承自INotifyUI接口 |
35 | public: |
36 | voidNotify(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 | intAPIENTRYWinMain(HINSTANCE hInstance, HINSTANCE/*hPrevInstance*/, LPSTR/*lpCmdLine*/, int nCmdShow) |
9 | { |
10 | CPaintManagerUI::SetInstance(hInstance); // 将程序实例与皮肤绘制管理器挂钩 |
11 | // 设置皮肤库的资源路径,资源有图片、xml文件等 |
12 | CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath() +TEXT("skin")); |
13 |
|
14 | HRESULTHr= ::CoInitialize(NULL); |
15 | if( FAILED(Hr) ) return0; |
16 |
|
17 | CHelloWorld* pHW =newCHelloWorld(); |
18 | if (pHW ==NULL) |
19 | return0; |
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 | return0; |
28 | } |
29 |
|
30 | CHelloWorld::CHelloWorld() |
31 | : m_pBtnOK(NULL) |
32 | , m_pBtnClose(NULL) |
33 | { |
34 |
|
35 | } |
36 |
|
37 | voidCHelloWorld::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 | voidCHelloWorld::OnOK() |
52 | { |
53 | Close(); // CWindowWnd继承来的函数Close,是关闭自己 |
54 | } |
55 |
|
56 | voidCHelloWorld::OnClose() |
57 | { |
58 | Close(); |
59 | } |
60 |
|
61 | LPCTSTRCHelloWorld::GetWindowClassName() const |
62 | { |
63 | returnTEXT("HelloWorld"); |
64 | } |
65 |
|
66 | UINTCHelloWorld::GetClassStyle() const |
67 | { |
68 | returnUI_CLASSSTYLE_FRAME|CS_DBLCLKS; |
69 | } |
70 |
|
71 | voidCHelloWorld::OnFinalMessage( HWND/*hWnd*/ ) |
72 | { |
73 | deletethis; |
74 | } |
75 |
|
76 | LRESULTCHelloWorld::HandleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam ) |
77 | { |
78 | LRESULT lRes =0; |
79 | BOOL bHandled =TRUE; |
80 | switch (uMsg) |
81 | { |
82 | caseWM_CREATE: |
83 | lRes =OnCreate(uMsg ,wParam, lParam, bHandled); |
84 | break; |
85 |
|
86 | caseWM_DESTROY: |
87 | ::PostQuitMessage(0); |
88 | bHandled =FALSE; |
89 | break; |
90 |
|
91 | caseWM_NCHITTEST: |
92 | lRes =OnNcHitTest(uMsg, wParam, lParam, bHandled); |
93 | break; |
94 |
|
95 | caseWM_KEYDOWN: |
96 | if (wParam ==VK_ESCAPE) |
97 | { |
98 | OnClose(); |
99 | } |
100 | break; |
101 |
|
102 | caseWM_SIZE: |
103 | lRes =OnSize(uMsg, wParam, lParam, bHandled); |
104 | break; |
105 |
|
106 | caseWM_NCACTIVATE: |
107 | lRes =OnNcActivate(uMsg, wParam, lParam, bHandled); |
108 | break; |
109 |
|
110 | caseWM_GETMINMAXINFO: |
111 | lRes =true; |
112 | OnGetMinMaxInfo(uMsg, wParam, lParam, bHandled); |
113 | break; |
114 |
|
115 | caseWM_SYSCOMMAND: |
116 | lRes =OnSysCommand(uMsg, wParam, lParam, bHandled); |
117 | break; |
118 |
|
119 | caseWM_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 | returnCWindowWnd::HandleMessage(uMsg, wParam, lParam); |
131 | } |
132 |
|
133 | LRESULTCHelloWorld::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 | return0; |
151 |
|
152 | } |
153 |
|
154 | LRESULTCHelloWorld::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 | return0; |
169 | } |
170 |
|
171 | LRESULTCHelloWorld::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 ) returnHTTOPLEFT; |
183 | if( pt.x > rcClient.right - rcSizeBox.right ) returnHTTOPRIGHT; |
184 | returnHTTOP; |
185 | } |
186 | elseif( pt.y > rcClient.bottom - rcSizeBox.bottom ) { |
187 | if( pt.x < rcClient.left + rcSizeBox.left ) returnHTBOTTOMLEFT; |
188 | if( pt.x > rcClient.right - rcSizeBox.right ) returnHTBOTTOMRIGHT; |
189 | returnHTBOTTOM; |
190 | } |
191 | if( pt.x < rcClient.left + rcSizeBox.left ) returnHTLEFT; |
192 | if( pt.x > rcClient.right - rcSizeBox.right ) returnHTRIGHT; |
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 | returnHTCAPTION; |
200 | } |
201 |
|
202 | returnHTCLIENT; |
203 | } |
204 |
|
205 | voidCHelloWorld::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 | elseif (msg.sType ==TEXT("windowinit")) |
215 | { |
216 | } |
217 | } |
218 |
|
219 | LRESULTCHelloWorld::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 | LRESULTCHelloWorld::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 | return0; |
241 | } |
242 |
|
243 | LRESULTCHelloWorld::OnSysCommand( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) |
244 | { |
245 | if (wParam ==SC_CLOSE) |
246 | { |
247 | bHandled =TRUE; |
248 | SendMessage(WM_CLOSE); |
249 | return0; |
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 | LRESULTCHelloWorld::OnNcCalcSize( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) |
264 | { |
265 | return0; |
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属性,固默认可以双击最大化。
S_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标识击中为客户区。
第一个duilib程序 - 实现HelloWorld详解的更多相关文章
- 每周一个linux命令之---uptime详解
每周一个linux命令之---uptime详解 linux命令 uptime详解 引言:从今天开始,每周更新一个对程序员有用的linux命令,我真的没敢写每天一个,我怕我坚持不下去,每周一个还是可以的 ...
- Python3调用C程序(超详解)
Python3调用C程序(超详解) Python为什么要调用C? 1.要提高代码的运算速度,C比Python快50倍以上 2.对于C语言里很多传统类库,不想用Python重写,想对从内存到文件接口这样 ...
- Spring Boot 之 HelloWorld详解
摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! “以前是人放狗看家,现在是狗牵着人散步” — 随笔 一.Spring Boot 自述 世界上最好 ...
- 微信小程序开发之详解生命周期方法
生命周期是指一个小程序从创建到销毁的一系列过程 在小程序中 ,通过App()来注册一个小程序 ,通过Page()来注册一个页面 先来看一张小程序项目结构 从上图可以看出,根目录下面有包含了app.js ...
- 一个经典的 HTTP协议详解
1引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1 ...
- MySQL程序之mysqlshow详解
mysqlshow命令详解 显示MySQL数据库的结构(数据库.表和列) 如果最后一个参数包含shell或SQL通配符(*,?,%,_)将显示通配符匹配的内容. 如果没有给定数据库,则显示所有匹配的数 ...
- MySQL程序只mysqlbinlog详解
mysqlbinlog命令详解 mysqlbinlog用于处理二进制的日志文件,如果想要查看这些日志文件的文本内容,就需要使用mysqlbinlog工具 用法: mysqlbinlog [option ...
- MySQL程序之mysqldump详解
mysqldump命令详解 mysqldump是mysql用于转存储数据库的实用程序.它主要产生一个SQL脚本,其中包含从头重新创建数据库所必需的命令CREATE TABLE INSERT等 用法: ...
- mysql程序之mysqladmin详解
mysqladmin命令 mysqladmin是执行管理操作的客户端.您可以使用它来检查服务器的配置和当前状态,以创建和删除数据库等 用法: mysqladmin [OPTIONS] command ...
随机推荐
- solr 如何实现精确查询
第一条和第三条不应该出现的. 解决办法
- java.lang.NoSuchMethodError: com.google.common.hash.HashFunction.hashInt(I)Lcom/google/common/hash/HashCode; 解决办法
今天在java 上运行spark查询的时候出现一个问题: java.lang.NoSuchMethodError: com.google.common.hash.HashFunction.hashIn ...
- 线性可分SVM中线性规划问题的化简
在网上找了许多关于线性可分SVM化简的过程,但似乎都不是很详细,所以凭借自己的理解去详解了一下. 线性可分SVM的目标是求得一个超平面(其实就是求w和b),在其在对目标样本的划分正确的基础上,使得到该 ...
- vue cli3使用webpack4打包优化
去掉console.log,以及开启gzip const CompressionPlugin = require('compression-webpack-plugin');//引入gzip压缩插件 ...
- linux下svn 客户端使用方式
输入 yes 开始 checkout服务器上的文件到本地目录 2.将文件 添加文件到某个目录下(是svn的服务器checkout下来的目录中) 3. 提交到服务器 4 .即可在服务器目录看到(wind ...
- 单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件)
webrtc的音频处理模块分为降噪ns和nsx,回音消除aec,回声控制acem,音频增益agc,静音检测部分.另外webrtc已经封装好了一套音频处理模块APM,如果不是有特殊必要,使用者如果要用到 ...
- thinkphp 模板注释
模板支持注释功能,该注释文字在最终页面不会显示,仅供模板制作人员参考和识别. 大理石平台厂家 单行注释 格式: {/* 注释内容 */ } 或 {// 注释内容 } 例如: {// 这是模板注释内容 ...
- The Preliminary Contest for ICPC Asia Nanjing 2019 C. Tsy's number 5
https://nanti.jisuanke.com/t/41300 题意:求\(\sum_{i=1}^n\phi(i)\phi(j)2^{\phi(i)\phi(j)}\) \(f_i=\sum_{ ...
- LUOGU P4394 [BOI2008]Elect 选举 (背包)
传送门 解题思路 一眼看上去就像个背包,然后就是\(0/1\)背包改一改,结果发现过不了样例.后来想了一下发现要按\(a\)从大到小排序,因为如果对于一个>=总和的一半但不满足的情况来说,把最小 ...
- Linux和Windows下ping命令详解
转:http://linux.chinaitlab.com/command/829332.html 一.Linux下的ping参数 用途 发送一个回送信号请求给网络主机. 语法 ping [ -d] ...