孙鑫老师VC++教程第一课笔记
2011-02-01 20:20
344 查看
看到有人说学编程的时候记了好几万字的笔记,让我心动不已,也想留点东西以后炫耀炫耀~其实这个也算不上笔记,算是一点记录吧,不过笔记的话也是有记点小东西在本子上的~嘿嘿~
----------------------------------------------------------------------------------------------------------------------------------------
终于把孙鑫老师VC++的教程的第一课看完了。最后面有15分钟左右的时间是复习,跟着写了一遍,但却漏洞百出。
先是复制在线MSDN的WinMain函数的参数出错,
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine, //应该要少一个W才对。
int nShowCmd //nCmdShow
)
自己查不出来这个错误,还是百度了,才知道,然后又自己写了一遍,跳出来的类型确实是LPSTR,约莫是VC6.0版本跟在线MSDN的版本不同吧。
然后又有单词拼错的问题。。。
总算编译通过了!可是,一直运行不了,出现的错误是0x77d3175b要调用0xcccccccc,但这个内存不能被read,百度,没有围绕这问题中心的答案,通过我一步一步的调试,觉得问题应该出在RegisterClass()这个函数执行的时候,再再百度,竟然有人跟我是一样的问题。。对wndcla.lpszMenuName没有赋值,所以RegisterClass在注册这个类的时候就出错了。于是更是无奈自己的马大哈,明明孙鑫老师在视频中就说过了,对结构体赋值完后要再检查一遍。
最后总算过了。。。哈哈~感觉真不错~代码如下,可以跳过不看:
-----------------------------------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
LRESULT CALLBACK WinWWProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
/*
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine, //应该要少一个W才对。
int nShowCmd //nCmdShow
)
*/
{
WNDCLASS wndcla;
wndcla.cbClsExtra=0;
wndcla.cbWndExtra=0;
wndcla.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
wndcla.hCursor=LoadCursor(NULL,IDC_CROSS);
wndcla.hIcon=LoadIcon(NULL,IDI_ERROR);
wndcla.hInstance=hInstance;
wndcla.lpfnWndProc=WinWWProc;
wndcla.lpszMenuName=NULL;//!错误地方!
wndcla.lpszClassName="w2003";
wndcla.style= CS_HREDRAW|CS_VREDRAW;
RegisterClass(&wndcla);
HWND hwnd;
hwnd=CreateWindow("w2003","快过年了",WS_OVERLAPPEDWINDOW,250,150,600,400,NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,SW_SHOWNORMAL);
UpdateWindow(hwnd);
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WinWWProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
switch(uMsg)
{
case WM_CHAR:
char strchar[500];
sprintf(strchar,"你按下了 %c 键",wParam);
MessageBox(hwnd,strchar,"我说:",0);
break;
case WM_LBUTTONDOWN:
MessageBox(hwnd,"你按了鼠标!","我说:",0);
HDC hdc;
hdc=GetDC(hwnd);
TextOut(hdc,100,100,"说了不能按鼠标你偏要按鼠标",strlen("说了不能按鼠标你偏要按鼠标"));
ReleaseDC(hwnd,hdc);
break;
case WM_PAINT:
HDC thdc;
PAINTSTRUCT ps;
thdc=BeginPaint(hwnd,&ps);
TextOut(thdc,95,222,"不能按鼠标",strlen("不能按鼠标"));
EndPaint(hwnd,&ps);
break;
case WM_CLOSE:
if(IDYES==MessageBox(hwnd,"你要离开?","确定",MB_YESNO))
{
DestroyWindow(hwnd);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
return 0;
}
-------------------------------------------------------------------------------------------------------------------------------
我感觉疑惑的是这一段。。
case WM_PAINT:
HDC thdc;
PAINTSTRUCT ps;
thdc=BeginPaint(hwnd,&ps);
TextOut(thdc,95,222,"不能按鼠标",strlen("不能按鼠标"));
EndPaint(hwnd,&ps);
break;
为什么要用Paint相关的函数,而不和上面
case WM_LBUTTONDOWN:
MessageBox(hwnd,"你按了鼠标!","我说:",0);
HDC hdc;
hdc=GetDC(hwnd);
TextOut(hdc,100,100,"说了不能按鼠标你偏要按鼠标",strlen("说了不能按鼠标你偏要按鼠标"));
ReleaseDC(hwnd,hdc);
break;
一样,用GetDC和ReleaseDC呢?
试着换了一下,
case WM_PAINT:
HDC thdc;
thdc=GetDC(hwnd);
// PAINTSTRUCT ps;
// thdc=BeginPaint(hwnd,&ps);
TextOut(thdc,95,222,"不能按鼠标",strlen("不能按鼠标"));
// EndPaint(hwnd,&ps);
ReleaseDC(hwnd,thdc);
break;
然后。。。运行结果:那一行“不能按鼠标”不停地抖阿抖,但界面却是死掉的,不管按什么都没反应,在开始栏右键也没反应,感觉像是程序在不断刷新,非常繁忙的感觉。
而把case WM_LBUTTONDOWN换成用PAINT相关,
case WM_LBUTTONDOWN:
MessageBox(hwnd,"你按了鼠标!","我说:",0);
HDC hdc;
// hdc=GetDC(hwnd);
PAINTSTRUCT pds;
hdc=BeginPaint(hwnd,&pds);
TextOut(hdc,100,100,"说了不能按鼠标你偏要按鼠标",strlen("说了不能按鼠标你偏要按鼠标"));
EndPaint(hwnd,&pds);
// ReleaseDC(hwnd,hdc);
break;
则不显示"说了不能按鼠标你偏要按鼠标"这一句话。
推了一下,怀疑是因为PAINT系列会自动销毁绘出的东西,而GetDC不会,但事实上还是很说不通,只能再百度啦~
百度结果如下:
BeginPaint() 和EndPaint() 可以删除消息队列中的WM_PAINT消息,并使无效区域有效。
GetDC()和ReleaseDC()并不删除也不能使无效区域有效,因此当程序跳出 WM_PAINT 时 ,无效区域仍然存在。系统就回不断发送WM_PAINT消息,于是程序不断处理WM_PAINT消息。
相当于BeginPaint、EndPaint会告诉GDI内部,这个窗口需要重画的地方已经重画了,这样WM_PAINT处理完返回给系统后,系统不会再重发WM_PAINT,而GetDC没有告诉系统这个窗口需要重画的地方已经画过,在你把程序返回给系统后,系统一直以为通知你的重画命令你还没有乖乖的执行或者执行出错,所以在消息空闲时,它还会不断地发WM_PAINT催促你画,导致程序卡死。
这下,我对这个消息有点困惑了,GetDC并没有告诉GDI已经重绘,不会自动删除WM_PAINT,然后WM_PAINT就不断循环,但难道这种没有删除WM_PAINT就不消失是它自己的特性么?不然为什么GetDC也没有删除WM_LBUTTONDOWN啊,它就不会循环。
然后我的困惑也进一步扩大,什么时候系统会获取到WM_PAINT消息呢?
待续吧~
再贴点知识~
无效区域 :
无效区域就是指需要重画的区域,无效的意思是:当前内容是旧的,过时的。
假设A是新弹出的一个对话框或被激活的现有对话框,A对话框置于原来的活动对话框B前面,造成对话框B的部分或全部被覆盖,当对话框A移开或关闭后,使对话框B原来被覆盖的地方重新可见。那部分被覆盖的地方就称为无效区域。
只有当一个窗口消息空闲时,系统才会抽空检查一下这个窗口的无效区域是否为非空(WM_PAINT的优先级是最低的。这也就是为什么系统很忙时窗口和桌面往往会出现变白、刷新不了、留拖拽痕迹等现象的原因),如果非空,系统就发送WM_PAINT。所以一定要用BeginPaint、EndPaint把无效区域设为空,否则WM_PAINT将一直被发送。
为什么WINDOWS要提出无效区域的概念?
这是为了加速。
因为BeginPaint和EndPaint用到的设备描述符只会在当前的无效区域内绘画,在有效区域内的绘画会自动被过滤,大家都知道,WIN GDI的绘画速度是比较慢的,所以能节省一个象素就节省一个,不用吝啬,这样可以有效加快绘画速度。
可见BeginPaint、EndPaint是比较“被动”的,只在窗口新建时和被摧残时才重画。
而GetDC用于主动绘制,只要你指到哪,它就打到哪。它不加判断就都画上去,无效区域跟它没关系。对话框没被覆盖没被摧残,它很健康,系统没要求它重画,但开发者有些情况下需要它主动重画:比如一个定时换外观的窗口,这时候就要在WM_TIMER处理代码用GetDC。这时候再用BeginPaint、EndPaint的话,会因为无效区域为空,所有绘画操作都将被过滤掉。
----------------------------------------------------------------------------------------------------------------------------------------
终于把孙鑫老师VC++的教程的第一课看完了。最后面有15分钟左右的时间是复习,跟着写了一遍,但却漏洞百出。
先是复制在线MSDN的WinMain函数的参数出错,
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine, //应该要少一个W才对。
int nShowCmd //nCmdShow
)
自己查不出来这个错误,还是百度了,才知道,然后又自己写了一遍,跳出来的类型确实是LPSTR,约莫是VC6.0版本跟在线MSDN的版本不同吧。
然后又有单词拼错的问题。。。
总算编译通过了!可是,一直运行不了,出现的错误是0x77d3175b要调用0xcccccccc,但这个内存不能被read,百度,没有围绕这问题中心的答案,通过我一步一步的调试,觉得问题应该出在RegisterClass()这个函数执行的时候,再再百度,竟然有人跟我是一样的问题。。对wndcla.lpszMenuName没有赋值,所以RegisterClass在注册这个类的时候就出错了。于是更是无奈自己的马大哈,明明孙鑫老师在视频中就说过了,对结构体赋值完后要再检查一遍。
最后总算过了。。。哈哈~感觉真不错~代码如下,可以跳过不看:
-----------------------------------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
LRESULT CALLBACK WinWWProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
/*
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine, //应该要少一个W才对。
int nShowCmd //nCmdShow
)
*/
{
WNDCLASS wndcla;
wndcla.cbClsExtra=0;
wndcla.cbWndExtra=0;
wndcla.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
wndcla.hCursor=LoadCursor(NULL,IDC_CROSS);
wndcla.hIcon=LoadIcon(NULL,IDI_ERROR);
wndcla.hInstance=hInstance;
wndcla.lpfnWndProc=WinWWProc;
wndcla.lpszMenuName=NULL;//!错误地方!
wndcla.lpszClassName="w2003";
wndcla.style= CS_HREDRAW|CS_VREDRAW;
RegisterClass(&wndcla);
HWND hwnd;
hwnd=CreateWindow("w2003","快过年了",WS_OVERLAPPEDWINDOW,250,150,600,400,NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,SW_SHOWNORMAL);
UpdateWindow(hwnd);
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WinWWProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
switch(uMsg)
{
case WM_CHAR:
char strchar[500];
sprintf(strchar,"你按下了 %c 键",wParam);
MessageBox(hwnd,strchar,"我说:",0);
break;
case WM_LBUTTONDOWN:
MessageBox(hwnd,"你按了鼠标!","我说:",0);
HDC hdc;
hdc=GetDC(hwnd);
TextOut(hdc,100,100,"说了不能按鼠标你偏要按鼠标",strlen("说了不能按鼠标你偏要按鼠标"));
ReleaseDC(hwnd,hdc);
break;
case WM_PAINT:
HDC thdc;
PAINTSTRUCT ps;
thdc=BeginPaint(hwnd,&ps);
TextOut(thdc,95,222,"不能按鼠标",strlen("不能按鼠标"));
EndPaint(hwnd,&ps);
break;
case WM_CLOSE:
if(IDYES==MessageBox(hwnd,"你要离开?","确定",MB_YESNO))
{
DestroyWindow(hwnd);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
return 0;
}
-------------------------------------------------------------------------------------------------------------------------------
我感觉疑惑的是这一段。。
case WM_PAINT:
HDC thdc;
PAINTSTRUCT ps;
thdc=BeginPaint(hwnd,&ps);
TextOut(thdc,95,222,"不能按鼠标",strlen("不能按鼠标"));
EndPaint(hwnd,&ps);
break;
为什么要用Paint相关的函数,而不和上面
case WM_LBUTTONDOWN:
MessageBox(hwnd,"你按了鼠标!","我说:",0);
HDC hdc;
hdc=GetDC(hwnd);
TextOut(hdc,100,100,"说了不能按鼠标你偏要按鼠标",strlen("说了不能按鼠标你偏要按鼠标"));
ReleaseDC(hwnd,hdc);
break;
一样,用GetDC和ReleaseDC呢?
试着换了一下,
case WM_PAINT:
HDC thdc;
thdc=GetDC(hwnd);
// PAINTSTRUCT ps;
// thdc=BeginPaint(hwnd,&ps);
TextOut(thdc,95,222,"不能按鼠标",strlen("不能按鼠标"));
// EndPaint(hwnd,&ps);
ReleaseDC(hwnd,thdc);
break;
然后。。。运行结果:那一行“不能按鼠标”不停地抖阿抖,但界面却是死掉的,不管按什么都没反应,在开始栏右键也没反应,感觉像是程序在不断刷新,非常繁忙的感觉。
而把case WM_LBUTTONDOWN换成用PAINT相关,
case WM_LBUTTONDOWN:
MessageBox(hwnd,"你按了鼠标!","我说:",0);
HDC hdc;
// hdc=GetDC(hwnd);
PAINTSTRUCT pds;
hdc=BeginPaint(hwnd,&pds);
TextOut(hdc,100,100,"说了不能按鼠标你偏要按鼠标",strlen("说了不能按鼠标你偏要按鼠标"));
EndPaint(hwnd,&pds);
// ReleaseDC(hwnd,hdc);
break;
则不显示"说了不能按鼠标你偏要按鼠标"这一句话。
推了一下,怀疑是因为PAINT系列会自动销毁绘出的东西,而GetDC不会,但事实上还是很说不通,只能再百度啦~
百度结果如下:
BeginPaint() 和EndPaint() 可以删除消息队列中的WM_PAINT消息,并使无效区域有效。
GetDC()和ReleaseDC()并不删除也不能使无效区域有效,因此当程序跳出 WM_PAINT 时 ,无效区域仍然存在。系统就回不断发送WM_PAINT消息,于是程序不断处理WM_PAINT消息。
相当于BeginPaint、EndPaint会告诉GDI内部,这个窗口需要重画的地方已经重画了,这样WM_PAINT处理完返回给系统后,系统不会再重发WM_PAINT,而GetDC没有告诉系统这个窗口需要重画的地方已经画过,在你把程序返回给系统后,系统一直以为通知你的重画命令你还没有乖乖的执行或者执行出错,所以在消息空闲时,它还会不断地发WM_PAINT催促你画,导致程序卡死。
这下,我对这个消息有点困惑了,GetDC并没有告诉GDI已经重绘,不会自动删除WM_PAINT,然后WM_PAINT就不断循环,但难道这种没有删除WM_PAINT就不消失是它自己的特性么?不然为什么GetDC也没有删除WM_LBUTTONDOWN啊,它就不会循环。
然后我的困惑也进一步扩大,什么时候系统会获取到WM_PAINT消息呢?
待续吧~
再贴点知识~
无效区域 :
无效区域就是指需要重画的区域,无效的意思是:当前内容是旧的,过时的。
假设A是新弹出的一个对话框或被激活的现有对话框,A对话框置于原来的活动对话框B前面,造成对话框B的部分或全部被覆盖,当对话框A移开或关闭后,使对话框B原来被覆盖的地方重新可见。那部分被覆盖的地方就称为无效区域。
只有当一个窗口消息空闲时,系统才会抽空检查一下这个窗口的无效区域是否为非空(WM_PAINT的优先级是最低的。这也就是为什么系统很忙时窗口和桌面往往会出现变白、刷新不了、留拖拽痕迹等现象的原因),如果非空,系统就发送WM_PAINT。所以一定要用BeginPaint、EndPaint把无效区域设为空,否则WM_PAINT将一直被发送。
为什么WINDOWS要提出无效区域的概念?
这是为了加速。
因为BeginPaint和EndPaint用到的设备描述符只会在当前的无效区域内绘画,在有效区域内的绘画会自动被过滤,大家都知道,WIN GDI的绘画速度是比较慢的,所以能节省一个象素就节省一个,不用吝啬,这样可以有效加快绘画速度。
可见BeginPaint、EndPaint是比较“被动”的,只在窗口新建时和被摧残时才重画。
而GetDC用于主动绘制,只要你指到哪,它就打到哪。它不加判断就都画上去,无效区域跟它没关系。对话框没被覆盖没被摧残,它很健康,系统没要求它重画,但开发者有些情况下需要它主动重画:比如一个定时换外观的窗口,这时候就要在WM_TIMER处理代码用GetDC。这时候再用BeginPaint、EndPaint的话,会因为无效区域为空,所有绘画操作都将被过滤掉。
相关文章推荐
- 孙鑫老师VC视频教程笔记1-10课
- 看孙鑫老师VC++视频教程笔记 之 多线程编程(一)
- 看孙鑫老师VC++视频教程笔记 之 多线程编程(三)
- 看孙鑫老师VC++视频教程笔记 之 多线程编程(二)
- 看孙鑫老师VC++视频教程笔记 之 多线程编程(一)
- 孙鑫VC教程学习笔记1
- java孙鑫老师视频教程笔记
- 孙鑫VC教程学习笔记1
- 孙鑫老师VC笔记大汇总(转)
- VC逃跑按钮SetWindowPos实现——看孙鑫老师教程的启发
- 孙鑫vc++ 第一课 笔记
- 观看 孙鑫 老师的《VC++ 深入编程视频教程》日记
- 孙鑫老师的VC++ 笔记11-16
- VC视频教程笔记(第一课)
- DLL编写(VC,孙鑫MFC教程笔记)
- 孙鑫vc学习笔记_第一课
- 孙鑫vc视频教程笔记(一) 之 VC++ MFC属性页使用说明
- 孙鑫vc++视频教程笔记之mfc输出卡拉ok变色字幕
- 【孙鑫Java教程笔记】第一课:Java…
- 孙鑫VC视频教程笔记之第十课“绘图”