【转】windows程序设计(14):鼠标消息详解
关于鼠标的一些细节知识:
通常,我们发消息时,都是对一个特定的窗口,但是对于鼠标消息却不然:只要鼠标跨越窗口或者在某窗口中按下鼠标按键,那么窗口消息处理程序就会收到鼠标消息,而不管该窗口是否活动或者是否拥有输入焦点。鼠标消息一个有21种:10个显示区域消息,11个非显示区域消息
显示区域鼠标消息
当鼠标移过窗口的显示区域时,窗口消息处理程序收到WM_MOUSEMOVE消息。
当在窗口的显示区域中按下或者释放一个鼠标按键时,窗口消息处理程序会接收到下面这些消息:
键 |
按下 |
释放 |
按下(双键) |
左 |
WM_LBUTTONDOWN |
WM_LBUTTONUP |
WM_LBUTTONDBLCLK |
中 |
WM_MBUTTONDOWN |
WM_MBUTTONUP |
WM_MBUTTONDBLCLK |
右 |
WM_RBUTTONDOWN |
WM_RBUTTONUP |
WM_RBUTTONDBLCLK |
只有对三键鼠标,窗口消息处理程序才会收到MBUTTON消息。
对于这些消息,其lParam值均含有鼠标的位置:低字字节为x坐标,高字节为y坐标,这两个坐标是相对于窗口显示区域左上角的位置。您可以用LOWORD和HIWORD宏来提取这些值:
x = LOWORD (lParam) ;
y = HIWORD (lParam) ;
wParam的值指示鼠标按键以及Shift和Ctrl键的状态:
MK_LBUTTON |
按下左键 |
MK_MBUTTON |
按下中键 |
MK_RBUTTON |
按下右键 |
MK_SHIFT |
按下Shift键 |
MK_CONTROL |
按下Ctrl键 |
举个例子,如果收到了WM_LBUTTONDOWN且wparam & MK_SHIFT为真,则说明左键按下时也按下了Shift键。
这里要强调一下:
1.WM_MOUSEMOVE消息:当您把鼠标移过窗口的显示区域时,Windows并不为鼠标的每个可能的图素位置都产生一个WM_MOUSEMOVE消息。您的程序接收到WM_MOUSEMOVE消息的次数,依赖于鼠标硬件,以及您的窗口消息处理程序在处理鼠标移动消息时的速度。换句话说,Windows不能用未处理的WM_MOUSEMOVE消息来填入消息队列。
2.对于WM_LBUTTONDOWN和WM_LBUTTONUP消息可能只收到一个!比如在一个窗口中按下鼠标按键,然后移动到使用者窗口释放它,就会出现这种情况。类似的情况,当鼠标按键在另一个窗口中被释放时,窗口消息处理程序只能接收到WM_LBUTTONDOWN消息,而没有相应的WM_LBUTTONUP消息。
3.关于双击鼠标:双击的间隔在控制面板里可以设置。但是是否需要相应“双击”则是我们自己写的:在注册窗口时,必须在窗口风格中包含CS_DBLCLKS标识符。这样当你双击时,系统会收到:
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDBLCLK
WM_LBUTTONUP
否则,只会收到:
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDOWN
WM_LBUTTONUP
看一个例子程序:
/*--------------------------------------------------CONNECT.C -- Connect-the-Dots Mouse Demo Program(c) Charles Petzold, 1998--------------------------------------------------*/#include <windows.h>#define MAXPOINTS 1000LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow)
{static TCHAR szAppName[] = TEXT ("Connect") ;HWND hwnd ;MSG msg ;WNDCLASS wndclass ;wndclass.style = CS_HREDRAW | CS_VREDRAW ;wndclass.lpfnWndProc = WndProc ;wndclass.cbClsExtra = 0 ;wndclass.cbWndExtra = 0 ;wndclass.hInstance = hInstance ;wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;wndclass.lpszMenuName = NULL ;wndclass.lpszClassName = szAppName ;if (!RegisterClass (&wndclass)){MessageBox (NULL, TEXT ("Program requires Windows NT!"), szAppName, MB_ICONERROR) ;return 0 ;}hwnd = CreateWindow (szAppName, TEXT ("Connect-the-Points Mouse Demo"),WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,NULL, NULL, hInstance, NULL) ;ShowWindow (hwnd, iCmdShow) ;UpdateWindow (hwnd) ;while (GetMessage (&msg, NULL, 0, 0)){TranslateMessage (&msg) ;DispatchMessage (&msg) ;}return msg.wParam ;
}LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{static POINT pt[MAXPOINTS] ;static int iCount ;HDC hdc ;int i, j ;PAINTSTRUCT ps ;switch (message){case WM_LBUTTONDOWN:iCount = 0 ;InvalidateRect (hwnd, NULL, TRUE) ;return 0 ;case WM_MOUSEMOVE://是否按下了左键且收到的点数不到1000if (wParam & MK_LBUTTON && iCount < 1000){//记录鼠标位置并在最后iCount+1pt[iCount ].x = LOWORD (lParam) ;pt[iCount++].y = HIWORD (lParam) ;hdc = GetDC (hwnd) ;//在指定的位置设置指定颜色的点SetPixel (hdc, LOWORD (lParam), HIWORD (lParam), 0) ;ReleaseDC (hwnd, hdc) ;}return 0 ;case WM_LBUTTONUP:InvalidateRect (hwnd, NULL, FALSE) ;return 0 ;case WM_PAINT:hdc = BeginPaint (hwnd, &ps) ;//画图时光标为等待状态SetCursor (LoadCursor (NULL, IDC_WAIT)) ;ShowCursor (TRUE) ;for (i = 0 ; i < iCount - 1 ; i++)for (j = i + 1 ; j < iCount ; j++){MoveToEx (hdc, pt[i].x, pt[i].y, NULL) ;LineTo (hdc, pt[j].x, pt[j].y) ;}ShowCursor (FALSE) ;SetCursor (LoadCursor (NULL, IDC_ARROW)) ;EndPaint (hwnd, &ps) ;return 0 ;case WM_DESTROY:PostQuitMessage (0) ;return 0 ;}return DefWindowProc (hwnd, message, wParam, lParam) ;
}
程序比较简单,就不多说了。
那什么是非显示区域的鼠标消息呢?如果鼠标在窗口的显示区域之外但还在窗口内,Windows就给窗口消息处理程序发送一条“非显示区域”鼠标消息。窗口非显示区域包括标题列、菜单和窗口滚动条。
这些消息通常我们是不用管的,将这些消息传给DefWindowProc,从而使Windows执行系统功能。
非显示区域鼠标消息几乎完全与显示区域鼠标消息相对应。消息中含有字母“NC”以表示是非显示区域消息。如果鼠标在窗口的非显示区域中移动,那么窗口消息处理程序会接收到WM_NCMOUSEMOVE消息。鼠标按键产生如表所示的消息:
键 |
按下 |
释放 |
按下(双击) |
左 |
WM_NCLBUTTONDOWN |
WM_NCLBUTTONUP |
WM_NCLBUTTONDBLCLK |
中 |
WM_NCMBUTTONDOWN |
WM_NCMBUTTONUP |
WM_NCMBUTTONDBLCLK |
右 |
WM_NCRBUTTONDOWN |
WM_NCRBUTTONUP |
WM_NCRBUTTONDBLCLK |
但是这些消息参数的意义却不同:
wParam参数指明移动或者按鼠标按键的非显示区域。
lParam参数的低位word为x坐标,高位word为y坐标,但是,它们是屏幕坐标。
最后一个消息是WM_NCHITTEST,它代表“非显示区域命中测试”,Windows应用程序通常把这个消息传送给DefWindowProc,系统会自动的判断你拖动的是标题栏还是边框而做出相应。
MFC一个解决自己发送WM_NCLBUTTONDOWN消息后收不到WM_ONLBUTTONUP的方法
MFC解决自己发送WM_NCLBUTTONDOWN消息收不到WM_LBUTTONUP的方法
最近在做一个MFC拖动窗口的程序,在网上搜到了一个方法,在OnLButtonDown里自己发送
PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x,point.y));
消息。这样一来确实能够在客户区移动窗口了,但是有一个问题:WM_LBUTTONUP消息被忽略了,写在OnLButtonUp里的内容根本没执行。在网上搜解决方法,要么是太复杂,要么没有很好的解决。最后自己试出了一个方法,经测试可行:
在OnNcLButtonDown函数里完成父类函数后自己发送一个WM_ONLBUTTONUP消息。
如下(CWnd应该换成你自己继承的父类,因为我直接从CWnd类继承过来 的,所以是CWnd):
1.处理左键按下消息函数:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point)
{RedrawWindow();Invalidate();//支持拖动PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x,point.y));CWnd::OnLButtonDown(nFlags, point);
}
这样就发送了非客户区左键按下的消息WM_NCLBUTTONDOWN。
2.处理非客户区左键按下消息函数:
afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point)
{CWnd::OnNcLButtonDown(nHitTest,point);PostMessage(WM_LBUTTONUP, NULL, NULL);
}
PostMessage(WM_LBUTTONUP, NULL, NULL)这一句就是自己发送左键放开的消息WM_LBUTTONUP。
根据这个结果,本人猜测CWnd::OnNcLButtonDown可能是要一直执行到鼠标放开时才结束,WM_LBUTTONUP被忽略了。这导致我们收不到WM_LBUTTONUP消息,所以在其后自己发送WM_LBUTTONUP后就能收到WM_LBUTTONUP消息了。
注意:
这个方法鼠标左键按下事件是有一秒左右延迟的,当把窗口移动到其他窗口上或控件上,松开再单击时可能会单击到那些窗口或控件,大家若有好的方法解决可以发下言。
【转】windows程序设计(14):鼠标消息详解相关推荐
- Windows XP 系统服务优化设置详解
Windows XP 系统服务优化设置详解(绝对精华) 分享XP_SP2服务详解及优化 XP_SP2服务详解及优化 个人认为XP的优化只有从服务着手,才是真正的优化,网上流传着一些方法,我 觉得根本就 ...
- [转]Windows下安全权限设置详解
一 Windows下安全权限设置详解 [简 介] 随着动网论坛的广泛应用和动网上传漏洞的被发现以及SQL注入式攻击越来越多的被使用,WEBSHELL让防火墙形同虚设,一台即使打了所有微软补丁.只让80 ...
- SVN的Windows和Linux客户端操作详解
SVN的Windows和Linux客户端操作详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Windows客户端操作 1.安装SVN客户端 a>.去官网下载svn软件 ...
- WPF中的鼠标事件详解
WPF中的鼠标事件详解 Uielement和ContentElement都定义了十个以Mouse开头的事件,8个以PreviewMouse开头的事件,MouseMove,PreviewMouseMov ...
- Windows命令:Net使用详解
[转帖]Windows命令:Net使用详解 Windows命令:Net使用详解 Windows 中的网络命令行的参数实在是够多也够复杂,当然其功能也是十分的强大,在某些场合下(如入侵到了某服务器^ ...
- windows批处理 (cmd/bat) 编程详解
2019独角兽企业重金招聘Python工程师标准>>> windows批处理 (cmd/bat) 编程详解 开始之前先简单说明下cmd文件和bat文件的区别:在本质上两者没有区别,都 ...
- 14.VisualVM使用详解、15.VisualVM堆查看器使用的内存不足、19.class文件--文件结构--魔数、20.文件结构--常量池、21.文件结构访问标志(2个字节)、22.类加载机制概
14.VisualVM使用详解 15.VisualVM堆查看器使用的内存不足 16.性能调优概述 17.性能调优–案例1 18.性能调优-案例三 19.class文件–文件结构–魔数 20.文件结构– ...
- mysql5.7.14安装版_MySql5.7.14安装教程详解(解压版)_MySQL
下面进入正式的教程: 第一步:下载最近的MySQL文件并且解压: 下载最新版的MySQL–mysql-5.7.12下载地址 将下载到的文件解压缩到自己喜欢的位置,例如我自己的位置是D:\MySQL\m ...
- 更多Windows Phone 8新功能详解
本文核心部分来自PocketNow,评价部分援引自We Love Windows Phone .HK的西門的评论,下面我们就来看一下具体内容. PocketNow发放独家新闻,指他们看过一段由Wind ...
最新文章
- Matlab与线性代数 -- 对角矩阵
- css和js实现3d图片,JavaScript_纯JS实现旋转图片3D展示效果,CSS:style type=text/cssgt - phpStudy...
- 推荐一波腾讯专家的技术书单,请收下!
- 如何通过 C# 生成安全的 Base64 URL 字符串?
- 从Spark Streaming到Apache Flink: 实时数据流在爱奇艺的演进 | 技术头条
- Java集合系列:Set解析
- Sublime Text 使用介绍、全套快捷键及插件推荐
- Effective C++ 读书笔记之Part4.Design and Declarations
- 引用类型-Function类型
- 光猫(吉比特h2-2)超级用户名与密码
- 给大家推荐一个资源库https://www.awesomes.cn/
- 汽车尾气污染检测 尾气烟雾检测
- Creo9.0 绘制中心线
- 我的创作纪念日(128天)
- 第二节HDFS完全分布式集群搭建与配置及常见问题总结
- 什么是邓氏编码DUNS NUMBER?
- ICLR 22 GRAPH CONDENSATION FOR GNNS 图压缩工作目前的 第一篇 密歇根州立 CMU Snap
- 无线网络监控分析工具
- 硕士卖房,到底是行业内卷,还是自我突破
- 0019_畸变矫正(单相机标定)
热门文章
- springboot创建子模块时遇到子模块覆盖父模块问题解决
- Luogu2439 [SDOI2005]阶梯教室设备利用 (动态规划)
- 私钥公钥学习心得(二)比特币与支付宝
- MyEclipse配色字体等配置的解决方案
- 如何编程得到数据库信息
- ASP.NET中使用非托管DLL
- html 常用字符,html 常用特殊字符
- ios php rsa,RSA 加密 iOS
- java 添加注解_你知道Java中的package-info的作用吗?
- micropython stm32f407 以太网_[MicroPython]STM32F407开发板DIY声光控开关