关于鼠标的一些细节知识:

通常,我们发消息时,都是对一个特定的窗口,但是对于鼠标消息却不然:只要鼠标跨越窗口或者在某窗口中按下鼠标按键,那么窗口消息处理程序就会收到鼠标消息,而不管该窗口是否活动或者是否拥有输入焦点。鼠标消息一个有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):鼠标消息详解相关推荐

  1. Windows XP 系统服务优化设置详解

    Windows XP 系统服务优化设置详解(绝对精华) 分享XP_SP2服务详解及优化 XP_SP2服务详解及优化 个人认为XP的优化只有从服务着手,才是真正的优化,网上流传着一些方法,我 觉得根本就 ...

  2. [转]Windows下安全权限设置详解

    一 Windows下安全权限设置详解 [简 介] 随着动网论坛的广泛应用和动网上传漏洞的被发现以及SQL注入式攻击越来越多的被使用,WEBSHELL让防火墙形同虚设,一台即使打了所有微软补丁.只让80 ...

  3. SVN的Windows和Linux客户端操作详解

    SVN的Windows和Linux客户端操作详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Windows客户端操作 1.安装SVN客户端 a>.去官网下载svn软件 ...

  4. WPF中的鼠标事件详解

    WPF中的鼠标事件详解 Uielement和ContentElement都定义了十个以Mouse开头的事件,8个以PreviewMouse开头的事件,MouseMove,PreviewMouseMov ...

  5. Windows命令:Net使用详解

      [转帖]Windows命令:Net使用详解 Windows命令:Net使用详解 Windows 中的网络命令行的参数实在是够多也够复杂,当然其功能也是十分的强大,在某些场合下(如入侵到了某服务器^ ...

  6. windows批处理 (cmd/bat) 编程详解

    2019独角兽企业重金招聘Python工程师标准>>> windows批处理 (cmd/bat) 编程详解 开始之前先简单说明下cmd文件和bat文件的区别:在本质上两者没有区别,都 ...

  7. 14.VisualVM使用详解、15.VisualVM堆查看器使用的内存不足、19.class文件--文件结构--魔数、20.文件结构--常量池、21.文件结构访问标志(2个字节)、22.类加载机制概

    14.VisualVM使用详解 15.VisualVM堆查看器使用的内存不足 16.性能调优概述 17.性能调优–案例1 18.性能调优-案例三 19.class文件–文件结构–魔数 20.文件结构– ...

  8. mysql5.7.14安装版_MySql5.7.14安装教程详解(解压版)_MySQL

    下面进入正式的教程: 第一步:下载最近的MySQL文件并且解压: 下载最新版的MySQL–mysql-5.7.12下载地址 将下载到的文件解压缩到自己喜欢的位置,例如我自己的位置是D:\MySQL\m ...

  9. 更多Windows Phone 8新功能详解

    本文核心部分来自PocketNow,评价部分援引自We Love Windows Phone .HK的西門的评论,下面我们就来看一下具体内容. PocketNow发放独家新闻,指他们看过一段由Wind ...

最新文章

  1. Matlab与线性代数 -- 对角矩阵
  2. css和js实现3d图片,JavaScript_纯JS实现旋转图片3D展示效果,CSS:style type=text/cssgt - phpStudy...
  3. 推荐一波腾讯专家的技术书单,请收下!
  4. 如何通过 C# 生成安全的 Base64 URL 字符串?
  5. 从Spark Streaming到Apache Flink: 实时数据流在爱奇艺的演进 | 技术头条
  6. Java集合系列:Set解析
  7. Sublime Text 使用介绍、全套快捷键及插件推荐
  8. Effective C++ 读书笔记之Part4.Design and Declarations
  9. 引用类型-Function类型
  10. 光猫(吉比特h2-2)超级用户名与密码
  11. 给大家推荐一个资源库https://www.awesomes.cn/
  12. 汽车尾气污染检测 尾气烟雾检测
  13. Creo9.0 绘制中心线
  14. 我的创作纪念日(128天)
  15. 第二节HDFS完全分布式集群搭建与配置及常见问题总结
  16. 什么是邓氏编码DUNS NUMBER?
  17. ICLR 22 GRAPH CONDENSATION FOR GNNS 图压缩工作目前的 第一篇 密歇根州立 CMU Snap
  18. 无线网络监控分析工具
  19. 硕士卖房,到底是行业内卷,还是自我突破
  20. 0019_畸变矫正(单相机标定)

热门文章

  1. springboot创建子模块时遇到子模块覆盖父模块问题解决
  2. Luogu2439 [SDOI2005]阶梯教室设备利用 (动态规划)
  3. 私钥公钥学习心得(二)比特币与支付宝
  4. MyEclipse配色字体等配置的解决方案
  5. 如何编程得到数据库信息
  6. ASP.NET中使用非托管DLL
  7. html 常用字符,html 常用特殊字符
  8. ios php rsa,RSA 加密 iOS
  9. java 添加注解_你知道Java中的package-info的作用吗?
  10. micropython stm32f407 以太网_[MicroPython]STM32F407开发板DIY声光控开关