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 ...
随机推荐
- JSON字符串——后台解析系列
以前我们都是讲JSON字符串获取后,在前台进行展示.今天小编就交给大家后台解析展示数据的方法.非常方便,就以下代码: JObject obj = JObject.Parse(data); string ...
- vim 插件管理
1 进入自己的vim mkdir ./bundle/vundle 2 在vimrc同级中执行 git clone https://github.com/gmarik/vundle.git ./bund ...
- Android下的数据储存方式(三)
Android下最好的数据储存方式:关系型数据库sqlite. 数据库的创建:使用SqliteOpenHelper类 结合SqliteOpenHelper类和SQLiteDatabase类的帮 ...
- Shell配置_配置IP
1.setup 打开图形化页面 a) 选择网络配置 b) 选择设置配置 c) 选择第一个网卡 2.启动网卡(第一个网卡) vim /etc/sysconfig/network-s ...
- 概率 高消light oj 1151
t个样例 n个楼梯或蛇; a b 刚好走到a会到b; 问走到100期望; dp[i] i到100的期望 这一点没奇怪的东西 dp[i]=1/6(dp[i+1]+dp[i+2]..+6); 有 ...
- jsrender for object
<div id="result"></div> <script id="theTmpl" type="text/x-js ...
- 系统间通信(9)——通信管理与RMI 下篇
接上文<架构设计:系统间通信(8)--通信管理与RMI 上篇>.之前说过,JDK中的RMI框架在JDK1.1.JDK1.2.JDK1.5.JDK1.6+几个版本中做了较大的调整.以下我们讨 ...
- IntelliJ IDEA 使用心得与常用快捷键
那种酸爽,根本说不出来—————————————————————————— by: Jimi没有BondJimi是谁? 就是洒家啊! 刚开始学习写Java的时候,用的eclipse,正式工作后,主 ...
- 【转】ListView学习笔记(一)——缓存机制
要想优化ListView首先要了解它的工作原理,列表的显示需要三个元素:ListView.Adapter.显示的数据: 这里的Adapter就是用到了适配器模式,不管传入的是什么View在ListVi ...
- 谷歌console开发人员官方文档(注意是谷歌)
https://developers.google.com/web/tools/chrome-devtools/debug/console/console-ui?hl=en#opening-the-c ...