孙鑫老师VC++教程第一课笔记

    技术2024-07-29  63

    看到有人说学编程的时候记了好几万字的笔记,让我心动不已,也想留点东西以后炫耀炫耀~其实这个也算不上笔记,算是一点记录吧,不过笔记的话也是有记点小东西在本子上的~嘿嘿~

    ----------------------------------------------------------------------------------------------------------------------------------------

    终于把孙鑫老师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的话,会因为无效区域为空,所有绘画操作都将被过滤掉。

     

    最新回复(0)