对WM_NCHITTEST消息的了解+代码实例进行演示(消息产生消息,共24个枚举值)
这个消息比较实用也很关键,它代表非显示区域命中测试。这个消息优先于所有其他的显示区域和非显示区域鼠标消息。其中lParam参数含有鼠标位置的x和y屏幕坐标,wParam 这里没有用。
Windows应用程序通常把这个消息传送给DefWindowProc,然后Windows用WM_NCHITTEST消息产生与鼠标位置相关的所有其他鼠标消息。通俗的讲从消息产生消息。
case WM_NCHITTEST:
return (LRESULT)HTNOWHERE;
以上代码能禁用窗口的所有显示区域和非显示区域鼠标消息,也就是当鼠标在窗口,这里包括系统菜单图标,缩放按钮,关闭按钮等时,鼠标按键将会失效。
先看一下这个消息的返回值吧:
One of the mouse hit-test enumerated values listed below.
下面列出的鼠标击中测试枚举值之一。
· HTBORDER 在不具有可变大小边框的窗口的边框上。
· HTBOTTOM 在窗口的水平边框的底部。
· HTBOTTOMLEFT 在窗口边框的左下角。
· HTBOTTOMRIGHT 在窗口边框的右下角。
· HTCAPTION 在标题条中。
· HTCLIENT 在客户区中。
· HTERROR 在屏幕背景或窗口之间的分隔线上(与HTNOWHERE相同,除了Windows的DefWndProc函数产生一个系统响声以指明错误)。
· HTGROWBOX 在尺寸框中。
· HTHSCROLL 在水平滚动条上。
· HTLEFT 在窗口的左边框上。
· HTMAXBUTTON 在最大化按钮上。
· HTMENU 在菜单区域。
· HTMINBUTTON 在最小化按钮上。
· HTNOWHERE 在屏幕背景或窗口之间的分隔线上。
· HTREDUCE 在最小化按钮上。
· HTRIGHT 在窗口的右边框上。
· HTSIZE 在尺寸框中。(与HTGROWBOX相同)
· HTSYSMENU 在控制菜单或子窗口的关闭按钮上。
· HTTOP 在窗口水平边框的上方。
· HTTOPLEFT 在窗口边框的左上角。
· HTTOPRIGHT 在窗口边框的右上角。
· HTTRANSPARENT 在一个被其它窗口覆盖的窗口中。
· HTVSCROLL 在垂直滚动条中。
· HTZOOM 在最大化按钮上。
关于这个消息的一个经典应用莫过于如何拖动一个无标题栏的窗体或者说我如何实现在客户区也能拖动此窗体,简单来说就是对WINDOWS进行了欺骗。
一个思考3秒就容易想到的方法是:处理鼠标消息WM_LBUTTONDOWN和WM_LBUTTONUP。在OnLButtonUp函数中计算鼠标位置的变化,调用MoveWindow实现窗口的移动。
PS:拖动标题栏移动窗口的时候,会出现一个矩形框,它提示了窗口移动的当前位置。当鼠标左键放开的时候,窗口就移动到矩形框所在位置。而我们刚才的那个的实现方案中没有这个功能。要实现此功能,我们必须自己来画这些矩形。事实上,我们没有必要自己来做这件事情,因为Windows已经给我们做好了。
试想,如果我能够欺骗Windows,告诉它现在鼠标正在拖动的是标题栏而不是客户区,那么窗口移动操作就由Windows来代劳了。
到这里这个消息就要闪亮登场了,前面说过了WM_NCHITTEST的消息响应函数会根据鼠标当前的坐标来判断鼠标命中了窗口的哪个部位,消息响应函数的返回值指出了部位,例如它可能会返回HTCAPTION,或者HTCLIENT等。
为了便于理解,先描述一下Windows对鼠标键按下的响应流程:
1. 确定鼠标键点击的是哪个窗口。Windows会用表记录当前屏幕上各个窗口的区域坐标,当鼠标驱动程序通知Windows鼠标键按下了,Windows根据鼠标的坐标确定它点击的是哪个窗口。
2. 确定鼠标键点击的是窗口的哪个部位。Windows会向鼠标键点击的窗口发送WM_NCHITTEST消息,来询问鼠标键点击的是窗口的哪个部位。(WM_NCHITTEST的消息响应函数的返回值会通知Windows)。通常来说,WM_NCHITTEST消息是系统来处理的,用户一般不会主动去处理它(也就是说,WM_NCHITTEST的消息响应函数通常采用的是Windows默认的处理函数)。
3. 根据鼠标键点击的部位给窗口发送相应的消息。例如:如果WM_NCHITTEST的消息响应函数的返回值是HTCLIENT,表示鼠标点击的是客户区,则Windows会向窗口发送WM_LBUTTONDOWN消息;如果WM_NCHITTEST的消息响应函数的返回值不是HTCLIENT(可能是HTCAPTION、HTCLOSE、HTMAXBUTTON等),即鼠标点击的是非客户区,Windows就会向窗口发送WM_NCLBUTTONDOWN消息。
这里有必要详细讨论一下:如果WM_NCHITTEST的消息响应函数的返回值是HTCAPTION,即指示了鼠标点击了标题栏,接下去Windows的处理是怎样的?
上面已经提到,接下来,Windows会向窗口发送WM_NCLBUTTONDOWN消息。
MSDN对WM_NCLBUTTONDOWN消息描述如下:
WM_NCLBUTTONDOWN
nHittest = (INT) wParam; // hit-test value
pts = MAKEPOINTS(lParam); // position of cursor
WM_NCLBUTTONDOWN的wParam指示了鼠标点击的窗口部位,lParam指示了当前鼠标的坐标。
如果应用程序没有对该消息响应,则由系统默认处理。
系统默认处理又是怎样的呢?系统发现wParam指示了鼠标点击的是标题栏,就会标识当前窗口处于“拖拽状态”(Windows内部记录了每个窗口的状态信息)。由于标识了“拖拽状态”,则从此刻起到鼠标键放开之前,你的鼠标移动状况完全由Windows跟踪。它根据鼠标的移动,使得窗口作“同步”移动。
注意,这个过程中,窗口不会收到WM_NCMOUSEMOVE消息,因为窗口和鼠标是“同步”移动的,你的鼠标相对于窗口是静止的。
最后再顺路提一下,如果想在右键这个窗体的时候弹出一个菜单, 当完成 MSG_WM_RBUTTONDOWN 这个消息的时候,发现窗体收不到这个消息, 将WM_NCHITTEST消息的实现去掉就可以了,原因是:
因为你在WM_NCHITTEST中处理了鼠标消息,把他定位成HTCAPTION,也就是鼠标在标题栏上,而标题栏属于非客户区(NC);
非客户区的事件消息都是以WM_NC开头的。也就是说,当你的WM_NCHITTEST返回HTCAPTION时,原来可以用WM_LBUTTONUP处理的消息,你只能用WM_NCLBUTTONUP来处理。
附加个例子吧
- #include <windows.h>
- #define DIVISIONS 5
- LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
- int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
- PSTR szCmdLine, int iCmdShow)
- {
- static TCHAR szAppName [] = TEXT ("RECT") ;
- HWND hwnd ;
- MSG msg ;
- WNDCLASS wndclass ;
- wndclass.style = CS_HREDRAW | CS_VREDRAW|CS_DBLCLKS ;//客户区想要响应双击,则CS_DBLCLKS得注册进去
- 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 ("This program requires Windows NT!"),
- szAppName, MB_ICONERROR) ;
- return 0 ;
- }
- hwnd = CreateWindow (szAppName, TEXT ("RECT TEST"),
- 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 ;
- }
- static int cxClient, cyClient;
- static BOOL state[DIVISIONS][DIVISIONS];
- LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- HDC hdc;
- HPEN hpen;
- PAINTSTRUCT ps ;
- RECT rect;
- int i,j;
- int x,y;
- //INT a;
- //char buf[10];
- char szAppName[]="RECTANGLE";
- LRESULT b;
- switch (message)
- {
- case WM_CREATE:
- //a=GetDoubleClickTime();
- //itoa(a,buf,10);
- //MessageBoxA(hwnd,buf,"hi",0);// 得到鼠标双击的间隔
- return 0 ;
- case WM_SIZE:
- cxClient = LOWORD (lParam)/DIVISIONS ;
- cyClient = HIWORD (lParam)/DIVISIONS ;
- //if(IsIconic(hwnd))
- //MessageBox(hwnd,TEXT("窗口已然最小化"),TEXT("情况"),0);
- //if(IsZoomed(hwnd))
- //MessageBox(hwnd,TEXT("窗口已然最大化"),TEXT("情况"),0);
- return 0 ;
- case WM_LBUTTONDBLCLK:
- POINT point;
- point.x=LOWORD(lParam);
- point.y=HIWORD(lParam);
- PostMessage(hwnd,WM_NCLBUTTONDBLCLK,HTCAPTION,MAKELPARAM(point.x,point.y));//实行欺骗
- //SetWindowPos(hwnd,
- return 0;
- case WM_LBUTTONDOWN:
- {
- x=LOWORD(lParam);
- y=HIWORD(lParam);
- i=j=0;
- while(!(x<i*cxClient))
- {
- ++i;
- }
- while(!(y<j*cyClient))
- {
- ++j;
- }
- if(state[i-1][j-1]==TRUE)
- {
- state[i-1][j-1]=FALSE;
- }
- else
- {
- state[i-1][j-1]=TRUE;
- }
- InvalidateRect(hwnd,NULL,TRUE);
- POINT point;
- point.x=LOWORD(lParam);
- point.y=HIWORD(lParam);
- PostMessage(hwnd,WM_NCLBUTTONDOWN,HTCAPTION,MAKELPARAM(point.x,point.y));//实行欺骗
- }
- return 0;
- case WM_PAINT:
- hdc=BeginPaint(hwnd,&ps);
- GetClientRect(hwnd,&rect);
- hpen=CreatePen(PS_SOLID,2,RGB(255,0,0));
- for(j=0;j<DIVISIONS;j++)
- for(i=0;i<DIVISIONS;i++)
- {
- Rectangle(hdc,i*cxClient,j*cyClient,(i+1)*cxClient,(j+1)*cyClient);
- if(state[i][j])
- {
- SelectObject(hdc,hpen);
- MoveToEx(hdc,i*cxClient,j*cyClient,NULL);
- LineTo(hdc,(i+1)*cxClient,(j+1)*cyClient);
- MoveToEx(hdc,i*cxClient,(j+1)*cyClient,NULL);
- LineTo(hdc,(i+1)*cxClient,j*cyClient);
- SelectObject(hdc,GetStockObject(BLACK_PEN));
- }
- }
- DeleteObject(hpen);
- EndPaint(hwnd,&ps);
- return 0 ;
- //case WM_NCLBUTTONDOWN:
- //return (LRESULT)HTCAPTION;
- case WM_NCHITTEST:
- b=DefWindowProc(hwnd,message,wParam,lParam);
- switch(b)
- {
- case HTCLIENT:
- SetWindowText(hwnd,TEXT("点击的是客户区"));
- return b;
- case HTCAPTION:
- SetWindowText(hwnd,TEXT("点击的是标题栏"));
- return b;
- case HTBOTTOM:
- SetWindowText(hwnd,TEXT("点击的是下边框"));
- return b;
- case HTBOTTOMLEFT:
- SetWindowText(hwnd,TEXT("点击的是左下边框"));
- return b;
- case HTCLOSE:
- SetWindowText(hwnd,TEXT("点击的是关闭按钮"));
- return b;
- case HTLEFT:
- SetWindowText(hwnd,TEXT("点击的是左边框"));
- return b;
- case HTMAXBUTTON:
- SetWindowText(hwnd,TEXT("点击的是最大化按钮"));
- return b;
- case HTMINBUTTON:
- SetWindowText(hwnd,TEXT("点击的是最小化按钮"));
- return b;
- case HTRIGHT:
- SetWindowText(hwnd,TEXT("点击的是右边框"));
- return b;
- case HTSYSMENU:
- SetWindowText(hwnd,TEXT("点击的是系统菜单"));
- return b;
- case HTTOP:
- SetWindowText(hwnd,TEXT("点击的是上边框"));
- return b;
- case HTBOTTOMRIGHT:
- SetWindowText(hwnd,TEXT("点击的是右下边框"));
- return b;
- default:
- return b;
- }
- case WM_DESTROY:
- PostQuitMessage (0) ;
- return 0 ;
- }
- return DefWindowProc (hwnd, message, wParam, lParam) ;
- }
对WM_NCHITTEST消息的了解+代码实例进行演示(消息产生消息,共24个枚举值)的更多相关文章
- ActiveMQ入门系列二:入门代码实例(点对点模式)
在上一篇<ActiveMQ入门系列一:认识并安装ActiveMQ(Windows下)>中,大致介绍了ActiveMQ和一些概念,并下载.安装.启动他,还访问了他的控制台页面. 这篇,就用代 ...
- php session 生命周期代码实例
php session 生命周期代码实例 我们为什么需要Session,就是因为我们需要存储各个用户的状态数据.那么试问,如果由你来设计解决这个需求的方案,那么也许你会设置这样一个数据 ...
- WinForm中 Asp.Net Signalr消息推送测试实例
p{ text-align:center; } blockquote > p > span{ text-align:center; font-size: 18px; color: #ff0 ...
- RabbitMQ入门:Hello RabbitMQ 代码实例
在之前的一篇博客RabbitMQ入门:认识并安装RabbitMQ(以Windows系统为例)中,我们安装了RabbitMQ并且对其也有的初步的认识,今天就来写个入门小例子来加深概念理解并了解代码怎么实 ...
- Java实现MD5加密及解密的代码实例分享
链接:http://www.jb51.net/article/86027.htm Java实现MD5加密及解密的代码实例分享 作者:厦门大学陈黎栋 字体:[增加 减小] 类型:转载 时间:2016-0 ...
- 【算法】禁忌搜索算法(Tabu Search,TS)超详细通俗解析附C++代码实例
01 什么是禁忌搜索算法? 1.1 先从爬山算法说起 爬山算法从当前的节点开始,和周围的邻居节点的值进行比较. 如果当前节点是最大的,那么返回当前节点,作为最大值 (既山峰最高点):反之就用最高的邻居 ...
- 网络编程之Socket代码实例
网络编程之Socket代码实例 一.基本Socket例子 Server端: # Echo server program import socket HOST = '' # Symbolic name ...
- MATLAB的PLOT函数线型设置及横坐标为字符串的代码实例
2.横坐标为字符串的代码实例 cell={‘PLS’,’SVM’,’RF’,’NNET’,’NB’,’PLR’,’C5.0′,’PDA’,’KNN’,’GLM’,’BCT’};%分类方法yData=[ ...
- web service上传参数代码实例
web service上传参数代码实例 这次做的项目用到webservice比较多,最开始在网上看的参考dome,发现都不行,后来发现安卓4.0以后有很大的不同,在做传参时,有些东西需要注意: 第一, ...
随机推荐
- 诡异的TNS-12541:TNS:nolistener
诡异的TNS-12541:TNS:nolistener OS:Microsoft Windows 2003 Ent ...
- poj 3154 Graveyard 贪心
//poj 3154 //sep9 #include <iostream> #include <cmath> using namespace std; double a[204 ...
- buffer cache chain 图
http://orabase.org/index.php/author/djeday84/page/7/
- 每天进步一点点——Linux
http://blog.csdn.net/cywosp/article/category/443566/1
- migrate from weblogic to tomcat: directory mapping--reference
Question: I am trying to migrate from weblogic to tomcat. in weblogic I have <virtual-directory-m ...
- 解密-神秘的 RunLoop
引言 一直以来RunLoop就是个神秘的领域,好多2.3年的开发者都不能准确的表述它的作用,说它神秘,其实RunLoop并没有大家想象中的那么神秘,那么不好理解,本文就带大家好好剖析一下”神秘的Run ...
- session绑定javaBean
1.HttpSessionBindingListener 这个监听器,可以让javaBean对象,感知它被绑定到session中或从session中移除.2.HttpSessionActivati ...
- Android开发--WIFI实现
wifi的基本结构 在Android的官方文档中定义了如下五种状态: WIFI_STATE_DISABLING WIFI网卡正在关闭 0 WIFI_STATE_DISABLED WIFI网卡不 ...
- 基于bootstrap的轮播广告页,带图片和文字
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8& ...
- 什么是mimeType?
因特网多媒体邮件扩展标示内容是什么格式.告诉浏览器或者server如何解析该数据http的请求和相应都含有一个mimeType字段 =>content-type(通用首部)