您的位置:首页 > 编程语言 > C语言/C++

孙鑫老师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的话,会因为无效区域为空,所有绘画操作都将被过滤掉。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: