从零开始学VC系列教程 五.消息机制与自定义消息【恢复】
从零开始学VC系列教程 五.消息机制与自定义消息 题外话:我们一再重复的讲Windows的消息,因为这的确是一个关键,会用,并且用好是非常必要的。这一章我们主要介绍一下消息机制及消息传输,做几个小小的实验,让大家在概念上明白怎么用。
本节内容:学会消息发送接收及自定义消息
学习目的: 撑握消息机制的概念,学会基于消息的操作.
这一章我们要做的例子看起来很简单,只是实现的方式不一样。按[开始]时,在文本框内显示当前的鼠标坐标,按[结束]后,显示一个结束信息,按[关闭]则退出程序.
1.新建工程.首先建一个基于MFC对话框的工程,名字为Eg05。前面四章我们已经介绍过很多次建立工程的方法了,这里不再重复了,如果还有不明白的,可以看一下以前的记录,或者给我留言。
2.在对话框上放一个EditBox,改ID称为IDC_EDIT_SHOW然后再添加三个按钮,分别设置标题为[开始],[结束],[关闭]。设置ID分别为IDC_BTN_STAR,IDC_BTN_OVER,IDC_BTN_CLOSE。通过前面几章的学习,我们知道ID号大家可以自己随便设定,当然最好是接近控件的作用简称或接近控件名的简称。完成后如下图所示。
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_588686.JPG
图片01 (原文件名:01.JPG)
首先我们来为[关闭]按钮添加响应,双击[关闭]按钮,添加响应程序。只有一行,呵呵。完成后如下图所示:
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_588687.JPG
图片02 (原文件名:02.JPG)
void CEg05Dlg::OnBtnClose()
{
// TODO: Add your control notification handler code here
PostMessage(WM_CLOSE);
}
编译运行,按[关闭]就可以看到程序退出了,晕死,是不是太简单了?下面我们来说一下为什么是这样。
在这里,我们用PostMessage函数发送了一个名为WM_CLOSE的消息,这是一个系统消息,用于关闭程序。查一查MSDN,可以看到这个函数的一些说明。原文放在下面,方便没有下载MSDN的朋友看看.
CWnd::PostMessage
BOOL PostMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 );
Return Value
Nonzero if the message is posted; otherwise 0.
Parameters
message
Specifies the message to be posted.
wParam
Specifies additional message information. The content of this parameter depends on the message being posted.
lParam
Specifies additional message information. The content of this parameter depends on the message being posted.
Remarks
Places a message in the window’s message queue and then returns without waiting for the corresponding window to process the message. Messages in a message
从原型我们可以看到,其实这个函数还有两个参数,分别为wParam和lParam,分别默认为0了。这两个参数是什么意思呢?
wParam和lParam 这两个是Win16系统遗留下来的产物,在Win16API中WndProc有两个参数:
一个是WORD类型的16位整型变量;另一个是LONG类型的32位整型变量。因此根据匈牙利命名法,16位的变量就被命名为wParam, 32位的变量就被命名为lParam。
到了Win32API中,原来的16位变量也被扩展为32位,因此此时wParam和lParam的大小完全相同。
在Win32API的早期,为了保证和Win16API的代码可移植性MS定义了WPARAM和LPARAM两个宏。
当时保留了w前缀的原因一方面是由于WPARAM宏也已W开头,还有也因为要提醒程序员注意到可移植性,当然到了现在Win16早已退出历史舞台,这个前缀也就约定俗成的沿用下来了。WPARAM 和 LPARAM 本质上没有什么区别:都是32位数, 但是区别也还是有的:除了上面说的关于16位的的历史问题外,MICROSOFT在使用时两种参数分别代表不同的含义和内容,WPARAM常常代表一些控件的ID或者高位低位组合起来分别表示鼠标的位置,如果消息的发送者需要将某种结构的指针或者是某种类型的句柄时,习惯上用LPARAM来传递,可以参考各种控件的通知消息。
在WM_CLSOE中,我们使用了不带参数的调用,其实这个消息本来也没有参数,所以后面的两个参数就默认了。
为了更好的说明这两个参数,下面我们来添加本例程的另一个功能,显示鼠标的坐标。其实显示坐标不用这么麻烦,在这里是为了更好的展示消息的参数。首先添加一个类变量,从类管理器中双击这个类,会打开这个类的头文件,在类定义中添加一个布尔变量,名称为m_bMouseMoveDisp完成后如下图所示
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_588688.JPG
图片03 (原文件名:03.JPG)
如上图,我们添加了两行代码。
public:
BOOL m_bMouseMoveDisp;
然后要对这个变量初始化,双击类管理器中的函数,可以打开对话框的初始化函数,我们在后面添加一行代码:m_bMouseMoveDisp=false; //这里就是变量初始化
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_588689.JPG
图片04 (原文件名:04.JPG)
下面要添加一个函数,选择,点右键会弹出一个菜单,如图所示
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_588690.JPG
图片05 (原文件名:05.JPG)
选择弹出一个对话框
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_588691.JPG
图片06 (原文件名:06.JPG)
然后在左边的列表中双击,可以看到这个函数添加到右边了,然后选择这个函数,双击或点最后一个按钮[编辑存在]就可以添加到类中了。完成后如图:
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_588692.JPG
图片07 (原文件名:07.JPG)
当然上面的图中,我们还添加了一些响应代码,
BOOL CEg05Dlg::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call the base class
if(pMsg->message==WM_MOUSEMOVE && m_bMouseMoveDisp==TRUE)
{
CString a;
a.Format("X坐标:%d,Y坐标:%d",pMsg->lParam&0x0000ffff,(pMsg->lParam&0xffff0000)>>16);
SetDlgItemText(IDC_EDIT_SHOW,a);
}
return CDialog::PreTranslateMessage(pMsg);
}
重载这个函数可以捕获本窗体的所有经过消息队列的消息,在win32程序中,关于消息有两种传递方式:
a.MFC消息,MFC会把所有的消息一条条放到一个AFX_MSGMAP_ENTRY结构中,形成一个数组,该数组存放了所有的消息和与它们相关的参数。也可以说是放到消息队列里去。
b. 采用SendMessage()或其他类似的方式向窗口直接发送的而不经过消息队列的消息。
这两种方式中只有第一种(穿过消息队列的消息)才受PreTranslateMessage()影响,
第二种消息并不会理睬PreTranslateMessage()的存在。
通过函数参数可以看到,传进来的是一个消息结构,我们查MSDN可以得到消息结构的原型:
typedef struct tagMSG { // msg
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG;
很明显,可以从message得到消息名称,所以我们写成if(pMsg->message==WM_MOUSEMOVE && m_bMouseMoveDisp==TRUE)在这里,m_bMouseMoveDisp是前面一步我们定义的类变量。当我们移动鼠标时,系统会发出一个名为WM_ MOUSEMOVE的消息到所有窗口,这个消息会经过消息队列,所以可以在这里捕获到,这个消息带两个参数,分别为
fwKeys = wParam; // key flags
xPos = LOWORD(lParam); // horizontal position of cursor
yPos = HIWORD(lParam); // vertical position of cursor
可以看到,lParam这个参数包括了光标所在处的坐标,而wParam则包含了鼠标键的事件,包括
MK_CONTROL Set if the ctrl key is down.
MK_LBUTTON Set if the left mouse button is down.
MK_MBUTTON Set if the middle mouse button is down.
MK_RBUTTON Set if the right mouse button is down.
MK_SHIFT Set if the shift key is down.
所在我们用pMsg->lParam&0x0000ffff取得参数lParam的低字节16位为X坐标,用,pMsg->lParam&0xffff0000)>>16的高16位数据,并移至低位作为Y坐标,然后嘛,大家都看得懂了,显示在IDC_EDIT_SHOW中。当然,这里还有一个条件,就是m_bMouseMoveDisp要为TRUE,这个就是按钮的事了,我们双击[开始]按钮,添加一行代码。bMouseMoveDisp=TRUE;完成后编译运行,点[开始]就可以看到框内显示了鼠标在窗体中的坐标了。实时效果如下:
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_588693.JPG
图片08 (原文件名:08.JPG)
要关闭坐标显示就很简单了,把m_bMouseMoveDisp置为FALSE就行了,所以大家可以为[结束]按钮添加一行代码就实现了。这里我们并不这样做,为了演示我们来绕一个大弯解决这个问题。按下这个按钮要发出一个消息WM_DISMOUSEDISP。很明显,这个消息是不存在的,我们自定义一个。双击,在前面添加一个定义。完成后如下图所示:
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_588694.JPG
图片09 (原文件名:09.JPG)
WM_USER 是windows自定义消息.一般一股是+几后再用。
如:#define WM_SHIT WM_USER+1
也就是说WM_USER是个分水岭,一般系统消息到不了这个数.在这里,我们自定义了一个消息,名为WM_DISMOUSEDISP
下面双击[结束]按钮,添加响应代码PostMessage(WM_DISMOUSEDISP);这里我们也不传参数了。从上面的分析大家可以看到,SendMessage也可以发送消息,但消息并不经过消息队列。这两个函数有点区别的。PostMessage只负责将消息放到消息队列中,不确定何时及是否处理
SendMessage要等到受到消息处理的返回码(DWord类型)后才继续
PostMessage执行后马上返回
SendMessage必须等到消息被处理后才会返回。
也就是说,我们发送的WM_DISMOUSEDISP可以通过PreTranslateMessage捕获到了。下面怎么写呢?想必大家也就明白了。以下给出响应代码。
BOOL CEg05Dlg::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call the base class
if(pMsg->message==WM_MOUSEMOVE && m_bMouseMoveDisp==TRUE)
{
CString a;
a.Format("X坐标:%d,Y坐标:%d",pMsg->lParam&0x0000ffff,(pMsg->lParam&0xffff0000)>>16);
SetDlgItemText(IDC_EDIT_SHOW,a);
}
if(pMsg->message==WM_DISMOUSEDISP && m_bMouseMoveDisp==TRUE)
{
m_bMouseMoveDisp=false;
SetDlgItemText(IDC_EDIT_SHOW,"关闭鼠标坐标显示!");
}
return CDialog::PreTranslateMessage(pMsg);
}
编译运行看看,是不是就可以了。
这一章先到这里了,在上一章中,我们提到过自定义消息及消息影射到函数,大家可以再回头看一下,加深理解。
下面是整个工程及教程的下载:
工程及教程下载ourdev_588704.rar(文件大小:2.30M) (原文件名:Eg5.rar)
第一章[从零开始学VC系列教程 一.信息显示实验]地址:http://ouravr.com/bbs/bbs_content.jsp?bbs_sn=1455135&bbs_page_no=1&search_mode=3&search_text=bqmcu&bbs_id=9999
第二章[从零开始学VC系列教程 二. 对话框及常用控件实验]地址:http://ouravr.com/bbs/bbs_content.jsp?bbs_sn=1481238&bbs_page_no=1&search_mode=3&search_text=bqmcu&bbs_id=9999
第三章[从零开始学VC系列教程 三. 串口通信及自定义消息]地址:http://ouravr.com/bbs/bbs_content.jsp?bbs_sn=1551606&bbs_page_no=1&search_mode=3&search_text=bqmcu&bbs_id=9999
第四章[从零开始学VC系列教程之 四.并口控制与类的使用]地址:http://ouravr.com/bbs/bbs_content.jsp?bbs_sn=1803655&bbs_page_no=1&search_mode=3&search_text=bqmcu&bbs_id=9999
非常感谢阿莫提供交流空间!! 找个沙发来,仔细的听,太棒了! 搬个凳子来听课! 支持ing!!! 等你这一课,等到花都谢了,楼主要提高生产效率啊 哈哈,顶…… VC和MSDN就不好传上来了,太大了,开始准备放在我自己网站上的,怕下载对服务器造成太大的负载。如果有需要可以加我QQ对传,飞雪浪子 570733482。
本贴被 Joyce 编辑过,最后修改时间:2009-01-17,10:15:20. 还有这么好的东西!!可惜最近学stm32,等闲点好好听课,先记号了。谢谢!! 非常感谢楼主!不过楼主能提供VC++那个软件更好,我都不知道去哪下。 这都有.前面还有4期. mark bqmcu 飞雪浪子
下一章决定调整为USB通信与USBASP下载软件编写.
================================================
赞一个!非常感谢你以实用为主的教程。 顶~ 支持! 支持! 继续支持!!! 谢谢你,楼主! 顶你下,坚持了这么久,请继续坚持下去
感谢 多谢多谢,想学点界面开发方面的知识,怎么灵活应用VC做程序界面 不错 顶你 先留下.要用时再看.... 最近缺课了,赶紧当漏得。
谢谢飞雪狼子! 下一章决定调整为USB通信与USBASP下载软件编写. 非常不错,很实用,一步步教你做工程! ding!!! 呵呵第六章~~ 等到花儿也谢了, 其实第六章的第一部分早写完了,只是自己读了很多次,越读越不满意,一直不敢发上来(怕砖头丢到脑袋上啊)。USB通信很难表达明白,说不清楚等于没说,还害了大家,误人子弟。虽然这样,第六章还是会在最迟一个星期就会与大家见面,能有这么多朋友支持,不敢不认真啊。这个部分很多方面的知识,包括读写文件,通信,存储等等,会分成几个步骤,几个部分陆续发布出来给大家,虽然速度没以前快了(最近出差太多)但一定会坚持到底。 其实第六章的第一部分早写完了,只是自己读了很多次,越读越不满意,一直不敢发上来(怕砖头丢到脑袋上啊)。USB通信很难表达明白,说不清楚等于没说,还害了大家,误人子弟。虽然这样,第六章还是会在最迟一个星期就会与大家见面,能有这么多朋友支持,不敢不认真啊。这个部分很多方面的知识,包括读写文件,通信,存储等等,会分成几个步骤,几个部分陆续发布出来给大家,虽然速度没以前快了(最近出差太多)但一定会坚持到底。
================================================
非常赞赏你的行为,你真是一个德艺双馨、德才兼备的技术人才。你是 our 的福。 第六章呢?浪子。我的邮箱Ranle_e@126.com 顶起 mark,慢慢研究! 支持一下 第六章呢?楼主,期待几个月了,呵呵!我的邮箱522190051@qq.com mark mark 感谢 前辈无私奉献 期待第6张啊 等待中........ 期待第6张啊,飞雪抓紧啊。 mark 很好 mark! 非常感谢 前五章学会了 十分感谢 现决定自己写一个试试 期待下一章!! 回复【楼主位】bqmcu 哆啦A梦
-----------------------------------------------------------------------
太感谢楼主了,虽然我工作3年了,但是刚刚入这行,是个愣头青,还是VC6用的亲切,教程很好。 感谢楼主,第六章啊 mark一下,有空再来看 真的是个好东西啊~非常感谢楼主~ 支持楼主,期待后续章节,楼主辛苦了
////////////////////////////////////////////////////////////////////////////////////////////////
标记
////////////// 楼主好久没冒泡了~ 没想到楼主在串口方面的学习学的很精细呀,向你学习{:handshake:} 我这第五章都下载不下了,不知道为什么
页:
[1]