【转】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消息了。

注意:

这个方法鼠标左键按下事件是有一秒左右延迟的,当把窗口移动到其他窗口上或控件上,松开再单击时可能会单击到那些窗口或控件,大家若有好的方法解决可以发下言。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/436115.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用多媒体库 Bass.dll 播放 mp3 [15] - 设置与获取播放速度

本例效果图:代码文件:unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls, ComCtrls;typeTForm1 class(TForm)OpenDialog1: TOpenDialog;Button1: TButton;Button2: TButton;Button3: TButton;TrackBar1:…

详解WINCE的控制面板

曾经在我的一篇《控制面板的创建》中介绍过WinCE控制面板的结构,不过由于那篇文章其目的只在于控制面板如何调用EXE程序,故对控制面板也仅是泛泛而谈.不过在这篇文章中,我们将对WinCE的使用方法来个整体的详解. 1.控制面板的结构 控制面板其实也是个动态链接库…

【转】设置Win32窗口背景颜色

窗口类结构体中&#xff0c;有一个窗口背景成员&#xff0c;hbrBackground。它是一个画刷句柄类型。在Windows中有各种各样的句柄&#xff0c;比如窗口句柄、实例句柄&#xff0c;画刷句柄&#xff0c;文件句柄等等&#xff0c;他们都是句柄类型&#xff0c;只是每一种句柄都和…

oracle中plsql块的结构,oracle plsql的结构

变量声明部分(没有变量可以不写declare)begin执行部分exception异常处理部分end*&#xff1a;declare 和 exception部分是可选的(1)PL/sql中变量的定义格式1变量名 变量类型 【约束】 default 默认值格式2变量名 变量类型 【约束】【&#xff1a;初始值】(2)一个简单的PL/sql块…

【转】Dicom文件解析!!!!!!

转自&#xff1a;https://blog.csdn.net/leaf6094189/article/details/8510325 Dicom全称是医学数字图像与通讯&#xff0c;这里讲的暂不涉及通讯那方面的问题 只讲*.dcm 也就是diocm格式文件的读取&#xff0c;读取本身是没啥难度的 无非就是字节码数据流处理。只不过确实比较…

VS2008 JS脚本调试总是调试旧代码 真不知道怎么回事?谁能帮帮我呀!

如图,[dynamic]标记的是调试的元文件 xml1.htm[dynamic]和xml.js[dynamic] 我更改后的文件是xml1.htm和xml.js,见图1 2 调试的文件有debugger 更改后的文件我把debugger注了 js脚本中我把变量给改了见3 4 ,所以在浏览新的xml1.htm时,竟然报对象找不到,真实受不了了!!! 为什么我…

蜂窝注册表和永久存储

WindowsCE有两种注册表&#xff0c;一种是基于RAM的&#xff0c;一种是基于蜂窝的注册表&#xff1b;WindowsCE会默认使用前者。如果是使用前者&#xff0c;PB在编译的时候会先把common.reg、platform.reg、project.reg及所有的.reg文件的内容合并到reginit.ini文件&#xff0c…

修改oracle默认日期,Oracle 修改默认日期格式

1、Oracle的日期格式Oracle数据缺省的时间格式数据的显示形式&#xff0c;与所使用的字符集有关。一般显示年月日&#xff0c;而不显示时分秒。例如&#xff0c;使用us7ascii字符集(或者是其他的英语字符集)时&#xff0c;缺省的时间格式显示为&#xff1a;28-Jan-2003&#xf…

【转】C#开发PACS医学影像处理系统(一):开发背景和功能预览

转自&#xff1a;https://www.cnblogs.com/Uncle-Joker/p/13646949.html 本系列文章将从以下模块和大家分享和讨论使用C#开发医学软件PACS和RIS系统&#xff0c; 国内相关资料比较少&#xff0c;也借此机会丰富一下医学软件开发生态&#xff0c;讨论技术难点&#xff0c;希望…

《WF编程》系列之30 - 基本活动:错误处理

《WF编程》系列之30 - 基本活动:错误处理 4.3 错误处理 Fault,故障,现在官方已经将其翻译为错误,那么以后的随笔中我也就采用官方的翻译吧. 错误处理也属于流程控制的一部分,这一节我来介绍一下有关错误处理的活动.错误是指在工作流执行期间发生的异常.我们可以使用错误处理程…

wince 自动启动程序设置

这是我在做wince6的时候为设置自启动而寻找的方法。我发现公司定的这个设备在“Program Files”和windows文件夹下放置的东西在机子重启之后就什么都没有了。我只有使用注册表测试&#xff0c;发现重启后还存在&#xff0c;因此我用注册表方式设置了自启动。而在这个过程中&…

oracle错误27101,ORA-27101ORA-01034错误解决

Oracle已经启动&#xff0c;连接sqlplus后&#xff0c;进行查询&#xff0c;出现下面错误ORA-01034: ORACLE not availableORA-27101: shared memory realm doesOracle已经启动&#xff0c;连接sqlplus后&#xff0c;进行查询&#xff0c;出现下面错误ORA-01034: ORACLE not av…

NOD32升级ID获取器For流星无语更新了

NOD32升级ID获取器For流星无语更新了一下,现在可以直接把用户名密码写入注册表了,连复制/粘贴操作都可以免了...转载于:https://www.cnblogs.com/lxwy/archive/2008/09/05/4420722.html

string也可以很精彩

// //TITLE: // string也可以很精彩 //AUTHOR: // norains //DATE: // Moday 03-November-2008 //Environment: // NONE // 对于习惯于MFC架构的朋友来说&#xff0c;估计直接采用API方式写代码最痛苦的莫过于没有CString。其实&#xff0c;在STL里面&#xff…

oracle存储过程行转列,oracle 存储过程-动态行转列,解决。

create or replace package body pro_test isprocedure Alarm_ContentsByTime(p_StartTime varchar2,----开始时间p_EndTime varchar2,----结束时间io_cursorinOUT out_cursor)iscursor cursor_1 IS--获取 列用于循环。select DISTINCT t.ps_productorcode code, t.PS_PRODUCTO…

【转】【C#】使用fo-dicom完成BMP,JPG,PNG图片转换为DICOM文件

转自&#xff1a;https://developer.aliyun.com/article/672065 最近研究了一下DICOM和BMP文件转换的问题&#xff0c;也是很头大。度娘了很久&#xff0c;也在CSDN等论坛看到一些断断续续的文件&#xff0c;最主要的是代码只是片断&#xff0c;不是完整的实现。头大了。 首先…

(转载)攻击方式学习之(1) - 跨站式脚本(Cross-Site Scripting)

原文地址&#xff1a;http://www.cnblogs.com/coderzh/archive/2008/09/06/1285500.html 声明&#xff1a;本文仅供学习研究之用&#xff0c;对于本文提到的某些网站的XSS漏洞&#xff0c;请读者发扬高尚的人道主义精神不要去危害他人&#xff0c;同时希望相应的网站能够尽快修…

C++设计模式之二 AbstractFactory模式

设计模式的目的就是尽量减少“变化”对程序的影响&#xff0c;尤其是对客户程序的影响。AbstractFactory模式作为创建型模式的一种&#xff0c;解决的就是“new”在变化中可能引起的问题。 先来看看new有何种不好&#xff0c;举个创建汽车的车门的例子&#xff1a; 很自然的一…

oracle win10配置命令,记一次Windows 平台下Oracle 10.2.0.5 EM重新配置

1. 删除EM资料库、dbconsole配置D:\>emca -deconfig dbcontrol db -repos dropEMCA 开始于 2013-2-20 9:53:17EM Configuration Assistant, 10.2.0.5.0 正式版版权所有 (c) 2003, 2009, Oracle。保留所有权利。输入以下信息:数据库 SID: ora10g监听程序端口号: 1521SYS 用户…

【转】Dicom 学习笔记-Dicom 消息服务(DIMSE-C/DIMSE-N)

转自&#xff1a;https://www.jianshu.com/p/2812b0b6e548 引言 DICOM(Digital Imaging and Communications in Medicine)医学数字成像与通信&#xff0c;是医疗影像领域一个非常重要的标准&#xff0c;本文主要简单介绍 DICOM 标准中的消息交换服务。在介绍之前先声明一下&am…