从当初说要学C++,学了两天放了俩月,真是无奈+悲剧。元旦放假,天气太冷,原计划再次骑行密云也无法成行了,只好在家继续猫着,正好再look下C++。
以前一直走的是弯路,如果要想学工作之外的东西,从底层语法开始一点点的走实在是费时费力的事情。无法连贯的看、写,效率极其低下。所有的语言语法结构等都差别不是很大,我感觉差距最大的在编译器上,不过这不是我们关心的了。所有掌握了最最基本的C++后,果断放弃语法。通过写程序,碰到的东西在回来学习思考,效率提高很多,而且不再枯燥无味。
好了,转入正题。
昨天用C++完成了一个初步的窗体和资源文件的建立与调用。用就了C#和Java,习惯了拖拽。对于这种较原始的方式感觉无比的不爽。但对于程序的执行方式,Windows的消息机制的理解是很有好处的。
昨天的知识复习:
一、Windows类
Windows类有两种:WNDCLASS和WNDCLASSEX后者是前者的扩展版,所以主要用的是WNDCLASSEX。
typedef struct _WNDCLASSEX
{
UINT cbSize;//结构大小
UINT style;//窗口的信息标志
WNDPROC lpfnWndProc;//事件函数
int cbClsExtra;//紧跟在窗口类结构后的附加字节数。
int cbWndExtra;//紧跟在窗口类结构后的附加字节数。
HANDLE hInstance;//模块的事例句柄
HICON hIcon;//图标的句柄
HCURSOR hCursor;//光标的句柄
HBRUSH hbrBackground;//背景画刷的句柄
LPCTSTR lpszMenuName;//指向菜单的指针
LPCTSTR lpszClassName;//指向类名称的指针
HICON hIconSm;//和窗口类关联的小图标
}
1 WNDCLASSEX winclass;
2
3 winclass.cbSize = sizeof(WNDCLASSEX);
4 winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
5 winclass.lpfnWndProc = WindowProc;
6 winclass.cbClsExtra = 0;
7 winclass.cbWndExtra = 0;
8 winclass.hInstance = hInstance;
9 winclass.hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_SKELETON));
10 winclass.hCursor = LoadCursor(hInstance,MAKEINTRESOURCE(IDC_XING));
11 winclass.hbrBackground = (HBRUSH)GetStockBrush(WHITE_BRUSH);
12 winclass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
13 winclass.lpszClassName = WINDOW_CLASS_NAME;
14 winclass.hIconSm = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_SKELETON));
创建窗口:
//生成窗体
if(!(hWnd = CreateWindowEx(NULL,
WINDOW_CLASS_NAME, //类名
"Window", //标题
WS_OVERLAPPEDWINDOW | WS_VISIBLE, //风格
200,200, //坐标
400,400, //大小
NULL,
NULL,
hInstance,
NULL)))
{
return 0;
}
二:事件机制
Windows的事件机制为当Windows运行任务时会产生事件和消息,所有的消息都进入一个队列,你窗口的消息会进入一个专门的队列中。你要做的就是从这些队列中取出消息并处理。Windows把最常用的消息做了处理,所以你可以只对你干兴趣的消息进行处理。
1 LRESULT CALLBACK WindowProc(HWND hWnd,
2 UINT msg,
3 WPARAM wparam,
4 LPARAM lparam)
5 {
6 PAINTSTRUCT ps;
7 HDC hdc;
8
9 switch(msg)
10 {
11 case WM_CREATE:
12 return 0;
13 break;
14 case WM_PAINT:
15 hdc = BeginPaint(hWnd,&ps);
16
17 EndPaint(hWnd,&ps);
18 break;
19 case WM_DESTROY:
20 PostQuitMessage(0);
21 return 0;
22 break;
23 case WM_KEYUP:
24 if(wparam == VK_F5)
25 {
26 //播放音乐
27 PlaySound(MAKEINTRESOURCE(IDR_WARP),hInstanceCpp,SND_RESOURCE | SND_SYNC);
28 }
29 break;
30 case WM_CLOSE:
31 MessageBox(hWnd,"关闭","消息",MB_OK | MB_ICONINFORMATION);
32 break;
33 case WM_COMMAND:
34 switch(LOWORD(wparam))
35 {
36 case MEN_NEW:
37 MessageBox(hWnd,"新建","消息",MB_OK | MB_ICONINFORMATION);
38 break;
39 case MEN_OPEN:
40 MessageBox(hWnd,"Open","消息",MB_OK | MB_ICONINFORMATION);
41 break;
42 }
43 break;
44 default: break;
45 }
46
47 return (DefWindowProc(hWnd,msg,wparam,lparam));
48 }
主事件循环的工作就是从消息队列中取消息经过初步处理后发生至消息处理函数。
1 //主事件循环
2 while(true)
3 {
4 if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
5 {
6 if(msg.message == WM_QUIT)
7 break;
8
9 TranslateMessage(&msg);
10
11 DispatchMessage(&msg);
12
13 }
14 }
取出消息队列有两种方式GetMessage()和PeekMeessage(),他们的区别在于前者取出后会删除消息队列中的消息而后者可以设置参数表明是否删除。
继续上面所说的无限循环问题,因为对应代码可知只有在有消息并取出时才会真正的执行循环,并不会消耗太多资源。另外很多时候消息队列是空闲的,如果只是等待确实不是个好主意可以在消息队列空闲时处理额外的事情,你要做的只是在上面加一个else。
四:资源的使用
只是看了些简单的时候,原理基本相同,打包成资源文件或存到硬盘,只要能取得句柄就ok。
好了,就到这里,边写边学对我来说应该是最适合的学习方法,学无止境。以前感觉用C#已经很牛了,可以做很多东西,但对于真正的系统级的东西了解太少了。C#的重点在于快速开发和减少程序员的工作。这方面它是成功的。但对于我来说则更倾向于大型游戏开发,这是我的一个梦想。
渐行渐近渐迷茫,
玉兔蹬春新年闹。
欲说寻梦今不悔,
同辈尽皆而立望。