• 【MFC】窗口消息与绘制(4)


    程序的入口为WinMain函数,其主要功能是注册窗口类、创建窗口、消息循环。要把握窗口程序的流程,重点应该放在窗口函数(消息处理)上,同时,对窗口的绘制也是需要掌握的重点。

    窗口消息

    常用窗口消息如下:

    消息名称

     

    WM_NULL 

    0x0000

    空消息,此消息将被接收窗口忽略

    WM_CREATE 

    0x0001

    应用程序创建一个窗口

    WM_DESTROY

    0x0002

    一个窗口被销毁

    WM_MOVE

    0x0003

    移动一个窗口

    WM_SIZE

    0x0005

    改变一个窗口的大小

    WM_ACTIVATE

    0x0006

    一个窗口被激活或失去激活状态

    WM_SETFOCUS

    0x0007

    获得焦点后

    WM_KILLFOCUS

    0x0008

    失去焦点

    WM_ENABLE

    0x000A

    应用程序Enable状态改变时产生

    WM_PAINT

    0x000F

    要求一个窗口重绘自己

    WM_CLOSE

    0x0010

    当一个窗口或应用程序要关闭时发送一个信号

    WM_QUIT

    0x0012

    用来结束程序运行或应用程序调用Postquitmessage()函数来产生此消息

    WM_SHOWWINDOW

    0x0018

    当隐藏或显示窗口是发送此消息给这个窗口

    WM_DRAWITEM

    0x002B

    ButtonComboBoxListboxMenu控件的外观改变时,发送此消息给这些控件的所有者

    WM_WINDOWPOSCHANGING

    0x0046

    当调用SetWindowPos()函数改变窗口的大小和位置后,发送此消息给该窗口

    WM_NOTIFY

    0x004E

    当某个控件的某个事件已经发生或这个控件需要得到一些信息时,发送此消息给它的父窗口

    WM_HELP

    0x0053

    当用户按下了F1,如果某个菜单是激活的,就发送此消息给此窗口关联的菜单,否则就发送给有焦点的窗口,如果当前都没有焦点,就把此消息发送给当前激活的窗口

    WM_CONTEXTMENU

    0x007B

    当用户在某个窗口中点击右键,则发送此消息给该窗口

    WM_KEYDOWN

    0x0100

    按下一个非系统键(按下键时未按下“ALT”键)

    WM_KEYUP

    0x0101

    释放一个非系统键

    WM_CHAR

    0x0102

    按下某键,当TranslateMessage()转发WM_KEYDOWN后发送本消息

    WM_COMMAND

    0x0111

    选择窗口菜单项或某个控件发送一条消息给它的父窗口或按下一个快捷键时产生此消息

    WM_TIMER

    0x0113

    发生了定时器事件

    WM_MOUSEMOVE

    0x0200

    鼠标移动

    WM_LBUTTONDOWN

    0x0201

    按下鼠标左键

    WM_LBUTTONUP

    0x0202

    释放鼠标左键

    WM_LBUTTONDBLCLK

    0x0203

    双击鼠标左键

    WM_RBUTTONDOWN

    0x0204

    按下鼠标右键

    WM_RBUTTONUP

    0x0205

    释放鼠标右键

    WM_RBUTTONDBLCLK

    0x0206

    双击鼠标右键

    WM_MBUTTONDOWN

    0x0207

    按下鼠标中键

    WM_MBUTTONUP

    0x0208

    释放鼠标中键

    WM_MBUTTONDBLCLK

    0x0209

    双击鼠标中键

    WM_MOUSEWHEEL

    0x020A

    当鼠标滚轮转动时发送此消息给当前获得焦点的窗口

    WM_USER

    0x0400

    帮助用户自定义消息,自定义消息可以为WM_USER+XX为正整数

     还有子窗口消息,如对话框中的控件消息。

    窗口绘制

    窗口绘制是通过GID + DC 一起来完成的。

    GDI 简单而言就是绘制的工具:画笔、画刷、字体、图片等等

    HFONT font = ::CreateFont(20,0,0,0,0,0,0,0,0,0,0,0,0,"楷体");
    HPEN    pen = ::CreatePen(PS_SOLID,5,RGB(0,0,255));

    DC 可以理解为绘制的场景(设备上下文):

    1、场景有两种:内存DC 和 显示DC,内存DC是没用直接完成显示的,显示DC则所有动作都会同步显示在窗口里。

    2、两种DC可以通过 “拷贝” 来完成场景的复制(内存拷贝到显示,即显示内存DC中的内容)

    3、有时候需要通过内存DC来消除窗口绘制过程中的 ”闪烁“ 问题,闪烁是因为多次直接在显示DC中绘制引起的。把所有需要绘制的动作(画线、输出文本、贴图等等)全部 ”暂存“ 在内存DC中完成,最后一次拷贝到显示DC。

    4、显示DC 的获取方法有两种:

       HDC dc =  ::GetDC(hWnd);  //从窗口句柄获取

       在响应WM_PAINT消息中:

        PAINTSTRUCT ps;//开始绘制
        HDC  hdc = ::BeginPaint(hWnd,&ps);

        ......

      ::EndPaint(hWnd,&ps);  //结束绘制,并回收资源

      5、内存DC与显示DC需要兼容:

          HDC hMenDC = ::CreateCompatibleDC(hdc);    

    6、记得释放DC资源:

    显示DC :::ReleaseDC(hdc)

    内存DC:::DeleteDC(hMenDC);

    示例

    在第一个窗口程序上完成自动切换指定的5张图片,再进行简单的文本、画线操作。

    分析:初始化GDI工具(字体、画笔、图片)放在WM_CREATE消息响应(创建窗口);

    开启定时器,这样每隔一段时间会收到系统的WM_TIMER 消息,响应WM_TIMER 随机选择一张图片,更新窗口即产生WM_PAINT消息

    WM_PAINT消息响应中绘制窗口。

    修改第一个窗口程序(整理版)Wndproc.h 头文件,添加三个函数

    1. #ifndef WNDPROC_H
    2. #define WNDPROC_H
    3. #include "main.h"
    4. LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
    5. WPARAM wParam, LPARAM lParam);
    6. void Render(HWND hWnd);
    7. void InitGdiObject(HWND hwnd);
    8. void DestroyGdiObjcet();
    9. #endif

    Wndproc.cpp进行相应的修改:

    1. #include "wndproc.h"
    2. #include "stdlib.h"
    3. #include "Mmsystem.h"
    4. #pragma comment(lib,"Winmm.lib")
    5. #include <stdio.h>
    6. HBITMAP bitmap[5];
    7. HFONT font;
    8. HPEN pen;
    9. int index = 0;
    10. LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
    11. WPARAM wParam, LPARAM lParam)
    12. {
    13. switch (message)
    14. {
    15. case WM_CREATE:
    16. InitGdiObject(hWnd);
    17. break;
    18. case WM_CLOSE:
    19. {
    20. ::DestroyWindow(hWnd);
    21. }
    22. break;
    23. case WM_DESTROY: //如果按下关闭按钮
    24. {
    25. PostQuitMessage(0); //发出关闭程序的消息
    26. DestroyGdiObjcet();
    27. break;
    28. }
    29. case WM_PAINT:
    30. {
    31. Render( hWnd);
    32. break;
    33. }
    34. case WM_TIMER:
    35. {
    36. RECT rect;
    37. ::srand(::timeGetTime());
    38. index=rand()%5;
    39. ::GetClientRect(hWnd,&rect);
    40. ::InvalidateRect(hWnd,&rect,TRUE);
    41. break;
    42. }
    43. default: //其他消息发给windows默认窗口处理函数
    44. return (DefWindowProc(hWnd,message,wParam,lParam));
    45. }
    46. return 0;
    47. }
    48. void Render(HWND hWnd)
    49. {
    50. PAINTSTRUCT ps;
    51. HDC hdc = ::BeginPaint(hWnd,&ps);
    52. HDC hMenDC = ::CreateCompatibleDC(hdc);
    53. ::SelectObject(hMenDC,bitmap[index]);
    54. ::SetStretchBltMode(hdc,COLORONCOLOR);
    55. ::StretchBlt(hdc,0,0,ps.rcPaint.right,ps.rcPaint.bottom,hMenDC,0,0,ps.rcPaint.right,ps.rcPaint.bottom,SRCCOPY);
    56. ::SelectObject(hdc,font);
    57. ::SetBkMode(hdc,TRANSPARENT);
    58. ::SetTextColor(hdc,RGB(255,0,0));
    59. ::TextOut(hdc,ps.rcPaint.right / 2 - 20,20,"My Second Appliaction",21);
    60. ::SelectObject(hdc,pen);
    61. ::MoveToEx(hdc,200,50,NULL);
    62. ::LineTo(hdc,ps.rcPaint.right-200,50);
    63. ::DeleteDC(hMenDC);
    64. ::EndPaint(hWnd,&ps);
    65. }
    66. void InitGdiObject(HWND hwnd)
    67. {
    68. char filename[256];
    69. RECT rect;
    70. ::GetClientRect(hwnd,&rect);
    71. for(int i=0;i<5;i++)
    72. {
    73. ::sprintf(filename,"%d.bmp",i+1);
    74. bitmap[i]=(HBITMAP)::LoadImage(NULL,filename,IMAGE_BITMAP,rect.right,rect.bottom,LR_LOADFROMFILE);
    75. }
    76. font = ::CreateFont(20,0,0,0,0,0,0,0,0,0,0,0,0,"楷体");
    77. pen = ::CreatePen(PS_SOLID,5,RGB(0,0,255));
    78. }
    79. void DestroyGdiObjcet()
    80. {
    81. for(int i=0;i<5;i++)
    82. ::DeleteObject(bitmap[i]);
    83. }

    其他消息的处理,建议多做测试,尤其是键盘、菜单、鼠标消息的处理。

  • 相关阅读:
    SpringBoot-接收参数相关注解
    嵌入式开发:5个可能不再被禁止的C特征
    【原创】xenomai UDD介绍与UDD用户态驱动示例
    UE4 利用WEBUI插件完成UE与JS的交互 (UE4嵌入WEB)
    小型气象站硬件和软件均采用模块组合式开放性设计,可灵活组合使用
    uniapp使用阿里图标显示查找文件失败,在H5端图标显示正常但是在移动端不显示图标的问题解决,uniapp中如何使用阿里巴巴图标库
    【Linux 内核分析课程作业 1】mmap 实现一个 key-valueMap
    【luogu CF1163F】Indecisive Taxi Fee(图论)(分类讨论)
    你不知道的测试小技巧——postman接口测试导入导出操作详解
    3.6 C++高级编程_异常
  • 原文地址:https://blog.csdn.net/yixiaobo2001/article/details/127833295