转自:

1.http://blog.sina.com.cn/s/blog_6b5180bf01012kbz.html

2.http://blog.csdn.net/happyhhb/article/details/1623278

3.http://njufsh.blog.163.com/blog/static/1917928162011103104222589/

孙鑫的MFC教程第4课主要讲了消息机制和MFC作图。

MFC使用一种消息映射机制来处理消息,在应用程序框架中的表现就是一个消息与消息处理函数一一对应的消息映射表,以及消息处理函数的声明和实现等代码。当窗口接收到消息时,会到消息映射表中查找该消息对应的消息处理函数,然后由消息处理函数进行相应的处理。SDK编程时需要在窗口过程中一一判断消息值进行相应的处理,相比之下MFC的消息映射机制要方便好用的多。

mfc在后台维护了一个句柄,以及程序各个类的句柄映射表,当我门在某个窗口上操作产生消息,该消息携带一个该窗口的句柄,通过该句柄找到该对象的指针,由窗口类传至父类,再由父类通过消息循环调用一个CWnd::WindowProc()
WindowProc()是一个虚函数,每个从CWnd继承的子类都有这样一个虚函数
WindowProc()调用了一个OnWndMsg(),该函数完成了主要的消息映射的处理
OnWndMsg()会辨别消息的种类,随后根据传过来的隐含的this指针来到类.h消息宏(DECLARE_MESSAGE_MAP()之上)查找有无对应的消息处理函数原形的声明,然后到类.cpp中的消息映射表(BEGIN_MESSAGE_MAP()和END_MESSAGE_MAP())中寻找有没有对应的处理函数,最终调用消息处理函数

消息响应会在3处修改代码

第一处是在头文件中

//{{AFX_MSG(CDrawView)

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

afx_msg void OnLButtonUp(UINT nFlags, CPoint point);

afx_msg void OnMouseMove(UINT nFlags, CPoint point);

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

另一处是cpp文件的begin MessageMap和End MessageMap之间

BEGIN_MESSAGE_MAP(CDrawView, CView)

//{{AFX_MSG_MAP(CDrawView)

ON_WM_LBUTTONDOWN()

ON_WM_LBUTTONUP()

ON_WM_MOUSEMOVE()

//}}AFX_MSG_MAP

// Standard printing commands

ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)

END_MESSAGE_MAP()

最后是要有函数实现的代码。

void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TOD Add your message handler code here and/or call default
m_ptOrigin=m_ptOld=point;
m_bDraw=TRUE;
CView::OnLButtonDown(nFlags, point);
}

利用HDC来作图

用菜单命令增加私有成员变量CPoint  m_ptOrigin=0; 初始化为0,响应鼠标左键按下函数为:

void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
// 按下去的时候是起点
m_ptOrigin = point;
CView::OnLButtonDown(nFlags, point);
}

用菜单命令增加鼠标左键up响应函数

void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CView::OnLButtonUp(nFlags, point);
}

这里面的点就是画线的终点;改变代码如下:

void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
//弹起来的时候是终点
HDC hdc;
hdc=::GetDC(m_hWnd);
//将设备移动到起点
MoveToEx(hdc, m_ptOrigin.x, m_ptOrigin.y, NULL);
LineTo(hdc, point.x, point.y);
//释放设备
::ReleaseDC(m_hWnd, hdc);
CView::OnLButtonUp(nFlags, point); }

以上我们采用了API函数,也就是全局函数来完成的;

API函数和类的成员函数都有ReleaseDC函数,所以调用API函数就要特别用作用域符号注明是API函数,如果不同名,则可以直接用;

用CDC类画线

MFC中所有画图的功能都集成到了CDC这个类中:

用CDC类绘制直线;

仍旧在View类里面捕获消息:

注意:画线的代码发生变化,其余步骤不变;

直接修改鼠标左键up响应函数

void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
//弹起来的时候是终点
CDC *pDC=GetDC();
//将设备移动到起点
pDC->MoveTo(m_ptOrigin);
pDC->LineTo(point);
//释放设备
ReleaseDC(pDC); CView::OnLButtonUp(nFlags, point);
}

以上我们采用了CDC类画线,看起来很简洁;

采用CClientDC画线

CClientDC类是从CDC这个类派生出来的;

优点:构造函数中调用GetDC;析构函数调用ReleaseDC;

也就是说用CClientDC类,就不用显示调用DetDC和ReleaseDC函数;

CClientDC绘制直线;

仍旧在View类里面捕获消息:

注意:画线的代码发生变化,其余步骤不变;

直接修改鼠标左键up响应函数

void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
//弹起来的时候是终点
CClientDC dc(this);
//将设备移动到起点
dc.MoveTo(m_ptOrigin);
dc.LineTo(point); CView::OnLButtonUp(nFlags, point);
}

以上我们采用了CClientDC类画线,看起来更简洁;

用this指针传递,表示在CDrawView上做图;

下面 我想和CMainFrame类相关,如何获取父窗口的指针?

void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
//弹起来的时候是终点
CClientDC dc(GetParent());//父类的,会在框架窗口,会画在工具栏上。
//将设备移动到起点
dc.MoveTo(m_ptOrigin);
dc.LineTo(point); CView::OnLButtonUp(nFlags, point);
}

采用CWindowDC画线

CWindowDC类是从CDC这个类派生出来的;

优点:构造函数中调用GetDC;析构函数调用ReleaseDC;

也就是说用CClientDC类,就不用显示调用DetDC和ReleaseDC函数;

可以访问整个屏幕区域,包括客户区和非客户区;

CWindowDC绘制直线;

仍旧在View类里面捕获消息:

注意:画线的代码发生变化,其余步骤不变;

直接修改鼠标左键up响应函数

void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
//弹起来的时候是终点
CWindowDC dc(GetParent());
//将设备移动到起点
dc.MoveTo(m_ptOrigin);
dc.LineTo(point); CView::OnLButtonUp(nFlags, point);
}

在标题栏+菜单栏上(非客户区)可以访问整个屏幕。

能否画到vc上,或者桌面上?

桌面本身就是一个窗口。

void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
//弹起来的时候是终点
CWindowDC dc(GetDesktopWindow());
//将设备移动到起点
dc.MoveTo(m_ptOrigin);
dc.LineTo(point); CView::OnLButtonUp(nFlags, point);
}

则可以画到vc上,或者桌面上;

CPen修改颜色

★如何画其他颜色的线条?

仍旧在View类里面捕获消息:

注意:画线的代码发生变化,其余步骤不变;

RGB这个宏 参数三个  红绿蓝 三个值的改变来调整颜色。

直接修改鼠标左键up响应函数

void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
//弹起来的时候是终点
CPen pen(PS_SOLID, , RGB(, , )); // 创建一个画笔
CClientDC dc(this);
CPen *pOldPen=dc.SelectObject(&pen); //这个笔选在设备表,返回的是原先的CPen
//将设备移动到起点
dc.MoveTo(m_ptOrigin); //移动到原点。
dc.LineTo(point); //终点
dc.SelectObject(pOldPen); //先前的画笔选择 CView::OnLButtonUp(nFlags, point);
}

这是画出红色的直线;

阴影线 粗细只能1或者更小

以下代码是设置新笔,保存旧的笔;

CPen *pOldPen=dc.SelectObject(&pen);

CBrush填充区域

★如何矩形区域区域颜色?

CBrush填充区域

仍旧在视类里面捕获消息:

注意:画线的代码发生变化,其余步骤不变;

直接修改鼠标左键up响应函数

void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CBrush brush(RGB(,,));
CClientDC dc(this);
dc.FillRect(CRect(m_ptOrigin, point), &brush);
//用指定的画刷来填充指定的矩形 ,当然也有自己缺省的画刷。
//不用将brush选中在设备描述表中。都是指定的!! 指定的画刷,指定的矩形区域。
CView::OnLButtonUp(nFlags, point);
}

这是画出红色的矩形;

位图画刷

首先要添加一个位图资源,insert菜单里面resource,添加new了一个Bitmap,它的资源ID是IDB_BITMAP1,程序如下:

void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP1); //加载这幅位图。
CBrush brush(&bitmap); //创建位图的画刷,位图对象的指针。
CClientDC dc(this);
dc.FillRect(CRect(m_ptOrigin, point), &brush); CView::OnLButtonUp(nFlags, point);
}

透明画刷

★如何矩形区域不相互遮挡?

CBrush透明画刷

仍旧在视类里面捕获消息:

注意:画线的代码发生变化,其余步骤不变;

直接修改鼠标左键up响应函数

void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));//获取透明画刷对象指针
CClientDC dc(this);
CBrush *pOldBrush=dc.SelectObject(pBrush); //将透明画刷选入DC
dc.Rectangle(CRect(m_ptOrigin,point)); //画矩形
dc.SelectObject(pOldBrush); //释放透明画刷 CView::OnLButtonUp(nFlags, point);
}

画出的矩形相互不遮挡,也就是透明的;

★★★★★注意点:

1)静态方法不属于某一个具体对象,而属于类本身,在类加载的时候就已经为类静态方法分配了代码去,故可用CBrush::FromHandle()形式调用。非静态的方法,是属于某个对象的。

2)静态方法中,不能引用非静态的数据成员和方法。

3)静态数据成员需要在类外单独做初始化,形式如: 变量类型 类名::变量名=初始值;

绘制曲线

★如何绘制拖动的曲线?

绘制拖动的曲线

第一步:增加一个BOOL m_bDraw;

在构造函数中m_bDraw=FALSE;

鼠标左键按下down响应函数中设置m_bDraw=TRUE;

用这个变量表示鼠标按下;

CDrawView::CDrawView()
{
// TODO: add construction code here
m_ptOrigin=;
m_bDraw=FALSE; //鼠标起来的时侯,构造函数初始化
}
void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
// 按下去的时候是起点
m_ptOrigin = point;
m_bDraw=TRUE; 鼠标按下去的时候 CView::OnLButtonDown(nFlags, point);
}

增加鼠标左键move响应函数,用右击菜单栏添加

void CDrawView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
if(m_bDraw==TRUE)
{
dc.MoveTo(m_ptOrigin); //移动到原点,就是第一次按下去的时候
dc.LineTo(point);
m_ptOrigin=point; //下一个起点就是上一个终点
} CView::OnMouseMove(nFlags, point);
}

MFC学习-第4课 消息机制和MFC作图的更多相关文章

  1. MFC学习(四) 消息机制

    1 消息机制的要点: 消息队列:先进先出 消息循环:通过循环while,不断的从消息队列中取得队首消息,并分发消息. 消息处理:根据不同的消息类型做不同的处理 事件:事件响应函数 2 消息机制 _tW ...

  2. windows消息机制(MFC)

    消息分类与消息队列 Windows中,消息使用统一的结构体(MSG)来存放信息,其中message表明消息的具体的类型, 而wParam,lParam是其最灵活的两个变量,为不同的消息类型时,存放数据 ...

  3. [转]windows消息机制(MFC)

    消息分类与消息队列 Windows中,消息使用统一的结构体(MSG)来存放信息,其中message表明消息的具体的类型, 而wParam,lParam是其最灵活的两个变量,为不同的消息类型时,存放数据 ...

  4. ios学习路线—Objective-C(Runtime消息机制)

    RunTime简称运行时.就是系统在运行的时候的一些机制,其中最主要的是消息机制.对于C语言,函数的调用在编译的时候会决定调用哪个函数( C语言的函数调用请看这里 ).编译完成之后直接顺序执行,无任何 ...

  5. VS下如何建立一个新的MFC程序 网络编程 课设 基于C++ MFC 连接数据库 小应用 小项目浅析展示

    原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/8191036.html 这里不知道会不会有人是真的新手 新新手 不知道怎么 如何建立一个MFC ...

  6. MFC学习-第一课 MFC运行机制

    最近由于兴趣爱好,学习了孙鑫的MFC教程的第一课.看完视频了,自己便用visual studio 2010尝试了MFC编程,其中遇到了一些问题. 1.vs2010不像vs6.0那样可以新建一个空的MF ...

  7. <MFC_1>深入剖析MFC的WinMain和消息机制

    一.开篇引论 熟悉Win32开发的朋友,应该非常了解它的基本组成和流程 1. WinMain:书写窗口类(WNDCLASS) -> 注册窗口类 -> 创建窗口 -> 显示窗口和更新窗 ...

  8. VJGUI消息设计-兼谈MFC、QT和信号/槽机制

    星期六下午4点,还在公司加班.终于写完了下周要交工的一个程序. 郁闷,今天这几个小时写了有上千行代码吧?虽然大部分都是Ctrl-C+Ctrl-V,但还是郁闷. 作为一个有10年经验的MFC程序员,郁闷 ...

  9. Android(java)学习笔记202:Handler消息机制的原理和实现

     联合学习 Android 异步消息处理机制 让你深入理解 Looper.Handler.Message三者关系   1. 首先我们通过一个实例案例来引出一个异常: (1)布局文件activity_m ...

随机推荐

  1. 【jQuery】Jquery.cookie()

    注意:如果不设置path,默认为当前路径,新建cookie $.cookie('name', 'value'); 新建带限制时间cookie $.cookie('name', 'value', { e ...

  2. ElasticSearch入门系列(四)分布式初探

    序言:ElasticSearch致力于隐藏分布式系统的复杂性,以下的操作都是在底层自动完成的: 将你的文档分区到不同的容器或者分片(shards),他们可以存在于一个或多个节点中 将分片均匀的分配到各 ...

  3. .NET中的GDI+

    GDI:Graphics Device Interface. System. Windows. Shapes 命名空间: 类 Ellipse 绘制一个椭圆. Line 在两个点之间绘制一条直线. Pa ...

  4. 1014mysqldumpslow.pl简单分析慢日志 WINDOW平台

    转自http://www.th7.cn/db/mysql/201507/113998.shtml 要想运行mysqldumpslow.pl(这是perl程序),下载perl编译器.下载地址:http: ...

  5. Mybatis学习--spring和Mybatis整合

    简介 在前面写测试代码的时候,不管是基于原始dao还是Mapper接口开发都有许多的重复代码,将spring和mybatis整合可以减少这个重复代码,通过spring的模板方法模式,将这些重复的代码进 ...

  6. 【HDU 5733】tetrahedron

    输入4个点三维坐标,如果是六面体,则输出内切球的球心坐标和半径. 点pi对面的面积为si,点a,b,c组成的面积=|ab叉乘ac|/2. 内心为a,公式: s0=s1+s2+s3+s4 a.x=∑si ...

  7. 操作系统也谈"算法"

    前言: 近来在准备校招的笔试面试,复习到操作系统时感觉概念性的东西比较多,不过对于以下的几类算法还是有必要做个小小总结. [作业调度算法] 先来先服务(FCFS, First Come First S ...

  8. 56. Android中进程优先级小结

    作为一个多任务的系统,Android 系统当然能够尽可能长的保留一个应用进程,但是由于新的或者更重要的进程需要更多的内存,系统不得不逐渐终结老的进程来获取内存.为了声明哪些进程需要保留,哪些需要kil ...

  9. Leetcode Bulb Switcher

    There are n bulbs that are initially off. You first turn on all the bulbs. Then, you turn off every ...

  10. 【BZOJ-3697&3127】采药人的路径&YinandYang 点分治 + 乱搞

    3697: 采药人的路径 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 681  Solved: 246[Submit][Status][Discus ...