MFC学习-第4课 消息机制和MFC作图
转自:
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作图的更多相关文章
- MFC学习(四) 消息机制
1 消息机制的要点: 消息队列:先进先出 消息循环:通过循环while,不断的从消息队列中取得队首消息,并分发消息. 消息处理:根据不同的消息类型做不同的处理 事件:事件响应函数 2 消息机制 _tW ...
- windows消息机制(MFC)
消息分类与消息队列 Windows中,消息使用统一的结构体(MSG)来存放信息,其中message表明消息的具体的类型, 而wParam,lParam是其最灵活的两个变量,为不同的消息类型时,存放数据 ...
- [转]windows消息机制(MFC)
消息分类与消息队列 Windows中,消息使用统一的结构体(MSG)来存放信息,其中message表明消息的具体的类型, 而wParam,lParam是其最灵活的两个变量,为不同的消息类型时,存放数据 ...
- ios学习路线—Objective-C(Runtime消息机制)
RunTime简称运行时.就是系统在运行的时候的一些机制,其中最主要的是消息机制.对于C语言,函数的调用在编译的时候会决定调用哪个函数( C语言的函数调用请看这里 ).编译完成之后直接顺序执行,无任何 ...
- VS下如何建立一个新的MFC程序 网络编程 课设 基于C++ MFC 连接数据库 小应用 小项目浅析展示
原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/8191036.html 这里不知道会不会有人是真的新手 新新手 不知道怎么 如何建立一个MFC ...
- MFC学习-第一课 MFC运行机制
最近由于兴趣爱好,学习了孙鑫的MFC教程的第一课.看完视频了,自己便用visual studio 2010尝试了MFC编程,其中遇到了一些问题. 1.vs2010不像vs6.0那样可以新建一个空的MF ...
- <MFC_1>深入剖析MFC的WinMain和消息机制
一.开篇引论 熟悉Win32开发的朋友,应该非常了解它的基本组成和流程 1. WinMain:书写窗口类(WNDCLASS) -> 注册窗口类 -> 创建窗口 -> 显示窗口和更新窗 ...
- VJGUI消息设计-兼谈MFC、QT和信号/槽机制
星期六下午4点,还在公司加班.终于写完了下周要交工的一个程序. 郁闷,今天这几个小时写了有上千行代码吧?虽然大部分都是Ctrl-C+Ctrl-V,但还是郁闷. 作为一个有10年经验的MFC程序员,郁闷 ...
- Android(java)学习笔记202:Handler消息机制的原理和实现
联合学习 Android 异步消息处理机制 让你深入理解 Looper.Handler.Message三者关系 1. 首先我们通过一个实例案例来引出一个异常: (1)布局文件activity_m ...
随机推荐
- Hotspot内存溢出测试
一.堆溢出 在执行代码时通过设置堆的最小值-Mms以及堆的最大值-Mmx来控制堆的大小,-XX参数dump出堆内存快照以便对内存溢出进行分析.通过创建大量对象来使堆溢出,当堆内存溢出时会提示OutOf ...
- 前端框架——BootStrap学习
BootStrap简单总结下:1.栅格系统,能够很好的同时适应手机端和PC端(及传说中的响应式布局) 2.兼容性好 接下来是对BootStrap学习的一些基础案例总结和回顾: 首先引入:bootstr ...
- 模块加载(require)及定义(define)时的路径
最近新公司在用requireJS进行JS的整合,刚开始接触有点蒙,于是深入了解了一下.requireJS主要是为了解决一下两个问题: (1)实现js文件的异步加载,避免网页失去响应: (2)管理模块之 ...
- JavaIO流文件的操作总结
IO流的分类 1.根据数据的流向: 输入流:用来读数据,如从外界设备读数据到内存中: 输出流:用来写数据,如从内存输出数据到外界存储设备: 2.根据数据流的格式: 字节流:一般用于声音或者秃瓢等二进制 ...
- openldap+phpadmin的搭建安装
1.概念介绍 LDAP是轻量目录访问协议,英文全称是Lightweight Directory Access Protocol,一般都简称为LDAP.它是基于X.500标准的,但是简单多了并且可以根据 ...
- Fiddler内置命令
我猜你肯定忽略了下边这个小黑框: 虽然它不是很显眼,但用好它,会让你的工作效率提高 N 倍! 这跟喜欢 Linux 的朋友一样,肯定更倾向于用一两个命令代替鼠标不断的点点点操作. Fiddler 将每 ...
- hdu2665 && poj2104划分树
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 47066 Accepted: 15743 Ca ...
- bootstrap 2.3版与3.0版的使用区别
bootstrap 2.3版与3.0版的使用区别 bootstrap已经推出了3.0的新版,看起来2.3.x版本也不会再更新了.那么bootstrap 2.3版与3.0版的区别在哪里呢?下面我们就来介 ...
- Android 高清加载巨图方案, 拒绝压缩图片
源地址:http://blog.csdn.net/lmj623565791/article/details/49300989 一.概述 距离上一篇博客有段时间没更新了,主要是最近有些私事导致的,那么就 ...
- 【POJ 1981 】Circle and Points
当两个点距离小于直径时,由它们为弦确定的一个单位圆(虽然有两个圆,但是想一想知道只算一个就可以)来计算覆盖多少点. #include <cstdio> #include <cmath ...