Windows-消息映射机制原理和简单的绘图技术

Windows-消息映射机制原理和简单的绘图技术

1.MFC消息映射机制

众所周知,Windows程序是基于消息编程的,但是在MFC中已经为我们封装好了这个框架的消息机制,我们需要了解它的实现原理,才能深入的学习和精通Visual C++。

**(1).消息映射机制的原理:

MFC消息映射机制的具体实现方法是,在每个能接收和处理消息的类中,定义一个消息和消息函数静态对照表,即消息映射表。在消息映射表中,消息与对应的消息处理函数指针是成对出现的。某个类能处理的所有消息及其对应的消息处理函数的地址都列在这个类所对应的静态表中。当有消息需要处理的时候,程序只要搜索该消息静态表,查看表中是否含有该消息,就可知道该类能否处理此消息。如果能处理该消息,则同样依照静态表能很容易找到并调用对应的消息处理函数。**

(2).在Visual C++中增加一个消息所需要的三处代码

头文件中第一处:

这里在头文件中定义了该类能够处理的消息

源文件中第二处:

源文件的开头定义该类的消息映射表

源文件中第三处:

这里源文件中消息的具体逻辑代码实现

(3).消息映射机制的底层实现过程

MFC在后台维护了一个窗口句柄与对应的C++对象指针的对照表,当窗口收到某个消息时,消息的第一个参数就指定了该消息和哪个窗口句柄相关,通过对照表,就可以找到与之相关的C++对象指针,然后把这个指针传递给应用程序框架窗口类的基类,后者会调用一个名为WindowProc的窗口过程函数,该函数的定义位于WinCore.cpp文件中,这个函数又会调用OnWndMsg函数在完成真正的消息路由,消息映射就是由此函数完成的。

WindProc

OnWndMsg代码过长,这里给出声明和文件路径,大家可以自己去分析,这里面的代码和用平台SDK编写一个窗口的回调函数是差不多的,就是对消息的判断和处理。

路径:C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\atlmfc\src\mfc\wincore.cpp

图解底层实现机制:

2.MFC绘制线条的几种方法

(1).利用Platform SDK全局函数绘制

    //平台的SDK,HDC是设备上下文
    HDC hdc = ::GetDC(m_hWnd);//获取DC
    MoveToEx(hdc, m_ptOrigin.x, m_ptOrigin.y, nullptr);
    LineTo(hdc, point.x, point.y);
    ::ReleaseDC(m_hWnd, hdc);//记得释放DC

(2).利用MFC的CDC类绘制

CDC类是MFC中一个专门用于绘图的类

    //需要手动管理CDC对象的创建和释放
    CDC* pDC = GetDC();//得到DC
    pDC->MoveTo(m_ptOrigin);
    pDC->LineTo(point);//画线的API
    ReleaseDC(pDC);//释放DC

(3).利用CClientDC

继承CDC,可以自动获取和释放DC

    //自动创建和释放CDC对象
    CClientDC dc(this);//画到视图窗口上
    dc.MoveTo(m_ptOrigin);
    dc.LineTo(point);

画在主窗口上

    //自动创建和释放CDC对象
    CClientDC dc(GetParent());//画到主窗口上
    dc.MoveTo(m_ptOrigin);
    dc.LineTo(point);

(4).利用CWindowDC

    //Windows屏幕的DC,画出的线条支持直接出现在屏幕上
    //CWindowDC dc(this);//画在视图上
    //CWindowDC dc(GetParent());//画在主框架窗口上

    dc.MoveTo(m_ptOrigin);
    dc.LineTo(point);

(5).在桌面窗口中画线

    CWindowDC dc(GetDesktopWindow());//直接画在屏幕上
    dc.MoveTo(m_ptOrigin);
    dc.LineTo(point);

(6).绘制彩色线条

    CPen pen(PS_DOT, 1, RGB(255, 1, 1));//画红色的点线
    CClientDC dc(this);
    CPen* pOldPen = dc.SelectObject(&pen);//保存先前的画笔,必要的一步 

    dc.MoveTo(m_ptOrigin);
    dc.LineTo(point); 

    dc.SelectObject(pOldPen);//恢复先前的画笔

(7).利用画刷CBrush绘图

    //画出图片bitmap
    CBitmap bitmap;
    //加载位图资源
    bitmap.LoadBitmap(IDR_MAINFRAME);//位图的资源ID
    CBrush brush(&bitmap);

    CClientDC dc(this);
    //填充矩形
    dc.FillRect(CRect(m_ptOrigin, point), &brush);

(8).绘制连续的线条

    CClientDC dc(this);
    if (m_bDraw)//m_bDraw是鼠标左键是否按下的BOOL成员变量,这里必须为TRUE
    {
        dc.MoveTo(m_ptOrigin);
        dc.LineTo(point);

        m_ptOrigin = point;//这次的终点作为下一次绘制线段的起点
    }

(9).绘制连续的带颜色的线条

    CClientDC dc(this);

    //改变画笔的颜色
    CPen pen(PS_SOLID, 1, RGB(255, 0, 0));
    CPen* pOldPen = dc.SelectObject(&pen); //将画笔选入设备描述表

    if (m_bDraw)//m_bDraw是鼠标左键是否按下的BOOL成员变量,这里必须为TRUE
    {
        dc.MoveTo(m_ptOrigin);
        dc.LineTo(point);
        m_ptOrigin = point;
    }

    dc.SelectObject(pOldPen);//恢复之前的画笔

(10).画扇形

    CClientDC dc(this);
    CPen pen(PS_SOLID, 1, RGB(255, 0, 0));
    CPen* pOldPen = dc.SelectObject(&pen);

    if (m_bDraw)
    {
        dc.MoveTo(m_ptOrigin);//起点不变,画出来的是扇形
        dc.LineTo(point);
    }

    dc.SelectObject(pOldPen);

(11).画出带边界的扇形

    CClientDC dc(this);
    CPen pen(PS_SOLID, 1, RGB(255, 0, 0));
    CPen* pOldPen = dc.SelectObject(&pen);

    if (m_bDraw)
    {
        dc.MoveTo(m_ptOrigin);
        dc.LineTo(point);
        dc.LineTo(m_ptOld);//这次的线段终点画到上一条线段的终点就可以形成边界
        m_ptOld = point;//保存上一条线段的终点
    }

    dc.SelectObject(pOldPen);

(12).画矩形

    //画出矩形并且使用画刷来填充颜色
    CClientDC dc(this);
    CBrush brush(RGB(255, 0, 0));
    dc.FillRect(CRect(m_ptOrigin, point), &brush); 

画透明的矩形

    CClientDC dc(this);
    //创建透明的画刷,GetStockObject返回的是HGDIOBJ,需要强制转换成HBRUSH,而且还需要将句柄转换成对象指针,要使用FromHandle
    //这个静态函数
    CBrush* pBrush = CBrush::FromHandle(static_cast<HBRUSH>(GetStockObject(NULL_BRUSH)));
    //保存旧的画刷
    CBrush* pOldBrush = dc.SelectObject(pBrush);
    //画出矩形
    dc.Rectangle(CRect(m_ptOrigin, point));
    //恢复旧的画刷
    dc.SelectObject(pOldBrush);

(13).设置绘图模式

    CClientDC dc(this);
    dc.SetROP2(R2_BLACK);//设置绘图的模式, 查看MSDN的详细介绍

3.MFCBuild

Build命令可以直接用F7来运行

4.总结

在使用MFC的时候,我们需要了解它的底层实现机制,这样我们在遇到问题的时候就知道是哪个环节出了问题,这是我们必经之路,另外在绘图的时候,需要清除我们画的的父视图是哪个。

下面是我总结的思维导图,方便大家形成良好的思维,一种有两个,是不同的时间做的。

(1).

(2).

图片的资源分享https://yunpan.cn/cPczaZE4HU5c4 访问密码 f09a

时间: 2024-10-10 09:30:59

Windows-消息映射机制原理和简单的绘图技术的相关文章

MFC编程入门之五(MFC消息映射机制概述)

在MFC软件开发中,界面操作或者线程之间通信都会经常用到消息,通过对消息的处理实现相应的操作.比较典型的过程是,用户操作窗口,然后有消息产生,送给窗口的消息处理函数处理,对用户的操作做出响应. 一.什么是消息?  窗口消息一般由三个部分组成:1.一个无符号整数,是消息值:2.消息附带的WPARAM类型的参数:3.消息附带的LPARAM类型的参数.其实,我们一般所说的消息是侠义上的消息值,也就是一个无符号整数,经常被定义为宏. 二.什么是消息映射机制?  MFC使用一种消息映射机制来处理消息,在应

VS2010/MFC编程入门之五(MFC消息映射机制概述)

VS2010/MFC编程入门之五(MFC消息映射机制概述)-软件开发-鸡啄米 http://www.jizhuomi.com/software/147.html     上一讲鸡啄米为大家简单分析了MFC应用程序框架,这一讲是关于MFC消息映射机制的内容.        前面已经说过,Windows应用程序是消息驱动的.在MFC软件开发中,界面操作或者线程之间通信都会经常用到消息,通过对消息的处理实现相应的操作.比较典型的过程是,用户操作窗口,然后有消息产生,送给窗口的消息处理函数处理,对用户的

MFC消息映射的原理:笔记

多态的实现机制有两种,一是通过查找绝对位置表,二是查找名称表:两者各有优缺点,那么为什么mfc的消息映射采用了第二种方法,而不是c++使用的第一种呢?因为在mfc的gui类库是一个庞大的继承体系,而里面的每个类有很多成员函数(只说消息反映相关的成员函数啊),而且在派生类中,需要改写的也比较少(我用来做练习的程序就是那么一两个,呵呵).那么用c++的虚函数的实现机制会导致什么问题呢?就是大量虚表的建立使得空间浪费掉很多. 嗯-怎么办呢?于是各大c++名库(比如QT,MFC,VCL-)在消息映射的实

x86平台上的Windows页表映射机制

首先,在x86架构的处理器上,一个正常页面大小为4KB,非PAE模式下,CR3持有页目录页面的物理地址,PDE和PTE格式相同大小为4字节.此时每个页表页面包含1024个PTE,可以映射1024个页面.而x86的4GB地址空间共包含1M个4KB的页面,映射所有这些页面共需要1024个页表页面,映射这1024个页表页面又需要1个页目录页面.乍看起来我们一共需要1025个页面来管理1M个页面的映射,其实不然. 我们不妨逆向理顺一下思路.首先,我们的地址空间中有1M=1024x1024个页面,而一个页

MFC消息映射机制

1 消息循环所在的函数 CWinApp::Run 2  消息类别 <1>Windows Messages WM_XX前缀开头,但是除了WM_COMMAND消息外. <2>Control Notifications 包含来自控件或者子窗口发给父窗口的 WM_COMMAND的通知消息. <3>Command Messages 菜单,工具栏按钮,快捷键 3 消息的发送和接受 CWinApp::Run函数接受消息并且将他们分派到合适的窗口,大多数命令消息时被发送到主框架窗口.接

C++MFC编程笔记day02 MFC消息映射机制、菜单资源使用

机制3:MFC消息映射机制: 类内声明,类外定义宏,绑定消息处理函数 派生自CCmdTarget 类内声明宏:DECLARE_MESSAGE_MAP() 类外添加实现宏: BEGIN_MESSAGE_MAP(类名,父类名) END_MESSAGE_MAP() //数据结构 struct AFX_MSGMAP_ENTRY { UINT nMessage;   // 消息ID UINT nCode;      // 通知码 UINT nID;        // 控件ID或消息 UINT nLast

消息映射机制

消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉. 一个消息,是系统定义的一个32位的值,它唯一地定义了一个事件,向Windows发出一个通知,告诉应用程序某个事情发生了. 例如,单击鼠标.改变窗口尺寸.按下键盘上的一个键都会使Windows发送一个消息给应用程序. 消息可以由系统或者应用程序产生. 系统在发生输入事件时产生消息. 举个例子, 当用户敲键, 移动鼠标或者单击控件. 系统也产生消息以响应由应用程序带来的变化, 比如应用程序改变系统字体改变窗体大小. 应用程序可

c++对MFC消息映射机制和运行时类型识别的理解

对MFC消息映射机制和运行时类型识别的理解 对MFC消息映射机制的理解 MFC中派生于Cobject的每个类都有一个消息映射表,所有MFC窗口都有一个同样的窗口过程AfxWndProc(),AfxWndProc的参数列表中有一个是窗口句柄,在AfxWndProc函数中将句柄(HWND)转换成了窗口指针(CWnd*),通过这个窗口指针就可以获得该窗口的消息映射表.对于WM_COMMAND这类特殊消息,将依据C++的虚函数多态机制来决定调用哪个类的函数. 对MFC运行时类型识别的理解 定义一个CRu

MFC消息映射机制详解

 MFC消息映射机制: 在每个能接收和处理消息的类中,定义一个消息与消息处理函数的映射表,即消息映射表.MFC有一个窗口句柄与C++对象指针的映射表,当窗口收到消息时,消息的第一个参数指明了该消息与哪个窗口句柄相关,通过映射表找到C++对象指针,然后将这个指针传递给应用程序框架窗口类的基类,基类调用WindowProc函数(在wincore.cpp文件中),这是一个虚函数,函数内部调用OnWndMsg函数,消息处理就是在这个函数内完成的,该函数也在wincore.cpp中.OnWndMsg函