Windows程序设计(七)--鼠标
7.2 客户区鼠标消息
当鼠标移过窗口的显示区域时,窗口消息处理程序收到WM_MOUSEMOVE消息。当在窗口的显示区域中按下或者释放一个鼠标按键时,窗口消息处理程序会接收到下面这些消息:
|
键 |
按下 |
释放 |
按下(双键) |
|
左 |
WM_LBUTTONDOWN |
WM_LBUTTONUP |
WM_LBUTTONDBLCLK |
|
中 |
WM_MBUTTONDOWN |
WM_MBUTTONUP |
WM_MBUTTONDBLCLK |
|
右 |
WM_RBUTTONDOWN |
WM_RBUTTONUP |
WM_RBUTTONDBLCLK |
要接受到双键消息,需要在wndclass.style处增加CS_DBLCLKS
在WM_MOUSEMOVE中,可以用LOWORD和HIWORD宏来提取鼠标的位置:
x = LOWORD (lParam) ;
y = HIWORD (lParam) ;
wParam中包含信息。MK前缀代表「鼠标按键」。
|
MK_LBUTTON |
按下左键 |
|
MK_MBUTTON |
按下中键 |
|
MK_RBUTTON |
按下右键 |
|
MK_SHIFT |
按下Shift键 |
|
MK_CONTROL |
按下Ctrl键 |
当您把鼠标移过窗口的显示区域时,Windows并不为鼠标的每个可能的图素位置都产生一个WM_MOUSEMOVE消息。您的程序接收到WM_MOUSEMOVE消息的次数,依赖于鼠标硬件,以及您的窗口消息处理程序在处理鼠标移动消息时的速度。
- 窗口消息处理程序可以「拦截鼠标」并且连续地接收鼠标消息,即使此时鼠标在该窗口显示区域之外。您将在本章的后面学习如何拦截鼠标。
- 如果正在显示一个系统模态消息框或者系统模态对话框,那么其它程序就不能接收鼠标消息。当系统模态消息框或者对话框活动时,禁止切换到其它窗口或者程序。一个显示系统模态消息框的例子,是当您关闭Windows时。
实例
#include<windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("Mouse Move");
HWND hwnd;
MSG msg;
WNDCLASS wndclass; wndclass.hInstance = hInstance;
wndclass.lpfnWndProc = WndProc;
wndclass.lpszClassName = szAppName;
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.lpszMenuName = ; if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("错误, 无法注册窗口类."), TEXT("错误"), MB_OK);
return ;
} hwnd = CreateWindow(szAppName, TEXT("Mouse Move"),
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , ))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static POINT pt[];
HDC hdc;
static int iCount;
PAINTSTRUCT ps;
int i, j; switch (message) {
case WM_LBUTTONDOWN:
iCount = ;
InvalidateRect(hwnd, NULL, TRUE);//重画时擦除背景
return ;
case WM_MOUSEMOVE:
if (wParam && MK_LBUTTON && iCount < ) {
pt[iCount].x = LOWORD(lParam);
pt[iCount++].y = HIWORD(lParam);
hdc = GetDC(hwnd);
SetPixel(hdc, LOWORD(lParam), HIWORD(lParam), );
ReleaseDC(hwnd, hdc);
}
return ;
case WM_LBUTTONUP:
InvalidateRect(hwnd, NULL, FALSE);//重画时不擦除背景
return ;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
SetCursor(LoadCursor(NULL, IDC_WAIT));
ShowCursor(TRUE);//显示鼠标
for (i = ; i < iCount - ; ++i) {
for (j = i + ; j < iCount; ++j) {
MoveToEx(hdc, pt[i].x, pt[i].y, NULL);
LineTo(hdc, pt[j].x, pt[j].y);
}
}
SetCursor(LoadCursor(NULL, IDC_ARROW));
ShowCursor(FALSE);//隐藏鼠标
EndPaint(hwnd, &ps);
} return DefWindowProc(hwnd, message, wParam, lParam);
}

7.2.2 处理shift
组合键测试
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_MOUSEMOVE:
if (wParam & MK_CONTROL) {
if (wParam & MK_SHIFT) {
MessageBox(hwnd, TEXT("按下Ctrl+Shift键"), TEXT("test!"), NULL);
return ;
}
}
} return DefWindowProc(hwnd, message, wParam, lParam);
}

7.2.3 鼠标双击
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_LBUTTONDBLCLK:
MessageBox(hwnd, TEXT("左键双击"), TEXT("test!"), NULL);
return ;
} return DefWindowProc(hwnd, message, wParam, lParam);
}

客户区鼠标消息简单应用
#include<windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("Mouse Move");
HWND hwnd;
MSG msg;
WNDCLASS wndclass; wndclass.hInstance = hInstance;
wndclass.lpfnWndProc = WndProc;
wndclass.lpszClassName = szAppName;
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.lpszMenuName = ; if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("错误, 无法注册窗口类."), TEXT("错误"), MB_OK);
return ;
} hwnd = CreateWindow(szAppName, TEXT("Mouse Move"),
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
, ,
NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , ))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int cxClient, cyClient;
static POINT point;
HDC hdc;
PAINTSTRUCT ps;
TCHAR szBuffer[]; switch (message) {
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return ;
case WM_MOUSEMOVE:
GetCursorPos(&point);
InvalidateRect(hwnd, NULL, TRUE);
return ;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, cxClient / - , cyClient / - , szBuffer, wsprintf(szBuffer, TEXT("屏幕坐标(%d, %d)"), point.x, point.y));
ScreenToClient(hwnd, &point);
TextOut(hdc, cxClient / - , cyClient / , szBuffer, wsprintf(szBuffer, TEXT("客户区坐标(%d, %d)"), point.x, point.y));
EndPaint(hwnd, &ps);
return ;
} return DefWindowProc(hwnd, message, wParam, lParam);
}

7.3 非客户区鼠标消息
|
键 |
按下 |
释放 |
按下(双击) |
|
左 |
WM_NCLBUTTONDOWN |
WM_NCLBUTTONUP |
WM_NCLBUTTONDBLCLK |
|
中 |
WM_NCMBUTTONDOWN |
WM_NCMBUTTONUP |
WM_NCMBUTTONDBLCLK |
|
右 |
WM_NCRBUTTONDOWN |
WM_NCRBUTTONUP |
WM_NCRBUTTONDBLCLK |
可以用两个Windows函数将屏幕坐标转换为显示区域坐标或者反之:
ScreenToClient (hwnd, &pt) ;
ClientToScreen (hwnd, &pt) ;
7.3.1 击中测试消息
WM_NCHITTEST,它代表「非显示区域命中测试」。此消息优先于所有其它的显示区域和非显示区域鼠标消息。lParam参数含有鼠标位置的x和y屏幕坐标,wParam 参数另有用途。
Windows应用程序通常把这个消息传送给DefWindowProc,然后Windows用WM_NCHITTEST消息产生与鼠标位置相关的所有其它鼠标消息。对于非显示区域鼠标消息,在处理WM_NCHITTEST时,从DefWindowProc传回的值将成为鼠标消息中的wParam参数,这个值可以是任意非显示区域鼠标消息的wParam值再加上以下内容:
|
HTCLIENT HTNOWHERE HTTRANSPARENT HTERROR |
显示区域 不在窗口中 窗口由另一个窗口覆盖 使DefWindowProc产生警示用的哔声 |
如果DefWindowProc在其处理WM_NCHITTEST消息后传回HTCLIENT,那么Windows将把屏幕坐标转换为显示区域坐标并产生显示区域鼠标消息。
#define HTERROR (-2) //在屏幕的后面或在窗体之间的线上(使函数DefWindowProc产生一个警示音)
#define HTTRANSPARENT (-1) //在一个被其它窗口覆盖的窗口中
#define HTNOWHERE 0 //在屏幕背景或窗口之间的分界线
#define HTCLIENT 1 //在客户区中
#define HTCAPTION 2 //在标题栏中
#define HTSYSMENU 3 //在一个窗口菜单栏或子窗口的关闭按钮上
#define HTGROWBOX 4 //在尺寸框中
#define HTSIZE HTGROWBOX //同HTGROWBOX
#define HTMENU 5 //在菜单区域
#define HTHSCROLL 6 //在水平滚动条上
#define HTVSCROLL 7 //在垂直滚动条上
#define HTMINBUTTON 8 //在最小化按钮上
#define HTMAXBUTTON 9 //在最大化按钮上
#define HTLEFT 10 //在窗口的左边框上
#define HTRIGHT 11 //在窗口的右边框上
#define HTTOP 12 //在窗口水平边框的上方
#define HTTOPLEFT 13 //在窗口边框的左上角
#define HTTOPRIGHT 14 //在窗口边框的右上角
#define HTBOTTOM 15 //在窗口的水平边框的底部
#define HTBOTTOMLEFT 16 //在窗口边框的左下角
#define HTBOTTOMRIGHT 17 //在窗口边框的右下角
#define HTBORDER 18 //在不具有可变大小边框的窗口的边框上
#define HTREDUCE HTMINBUTTON //同HTMINBUTTON
#define HTZOOM HTMAXBUTTON //同HTMAXBUTTON
#define HTSIZEFIRST HTLEFT //同HTLEFT
#define HTSIZELAST HTBOTTOMRIGHT //同HTBOTTOMRIGHT
#define HTOBJECT 19 //忽略该标识符, 已废弃
#define HTCLOSE 20 //在关闭按钮上
#define HTHELP 21 //在帮助按钮上
#include<windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("Mouse Move");
HWND hwnd;
MSG msg;
WNDCLASS wndclass; wndclass.hInstance = hInstance;
wndclass.lpfnWndProc = WndProc;
wndclass.lpszClassName = szAppName;
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.lpszMenuName = ; if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("错误, 无法注册窗口类."), TEXT("错误"), MB_OK);
return ;
} hwnd = CreateWindow(szAppName, TEXT("Mouse Move"),
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
, ,
NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , ))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
TCHAR szBuffer[];
static POINT pt; switch (message) {
case WM_NCLBUTTONDOWN:
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
ScreenToClient(hwnd, &pt);
switch (wParam) {
case HTCAPTION:
wsprintf(szBuffer, TEXT("击中标题栏,客户区坐标(%d, %d)"), pt.x, pt.y);
MessageBox(hwnd, szBuffer, TEXT("test"), NULL);
break;
case HTMINBUTTON:
wsprintf(szBuffer, TEXT("击中最小化,客户区坐标(%d, %d)"), pt.x, pt.y);
MessageBox(hwnd, szBuffer, TEXT("test"), NULL);
break;
case HTMAXBUTTON:
wsprintf(szBuffer, TEXT("击中最大化,客户区坐标(%d, %d)"), pt.x, pt.y);
MessageBox(hwnd, szBuffer, TEXT("test"), NULL);
break;
}
return ;
} return DefWindowProc(hwnd, message, wParam, lParam);
}

Windows程序设计(七)--鼠标的更多相关文章
- Windows程序设计学习笔记(1):一个简单的windows程序
<Windows程序设计>(第五版)(美Charles Petzold著) #include<windows.h> LRESULT CALLBACK WndProc(HWND, ...
- Windows 程序设计(4) MFC 03 -系列学习
本文整体目录和绝大部门内容来自 [鸡啄米网站]的MFC系列文章,欢迎支持原创 (一)VS2010/MFC编程入门之前言 VC++全称是Visual C++,是由微软提供的C++开发工具,它与C++的根 ...
- Windows 程序设计
一.Win32 API /******************************************************************** created: 2014/04/1 ...
- 关于《Windows程序设计(第五版)》中一个实例程序的疑问
最近一直在看Charlse Petzold的<Windows程序设计>,作为一个新得不能再新的新手,只能先照着书的抄抄源码了,之前的例子一直都很正常,但昨天遇到一个很诡异的BUG. 先看实 ...
- windows 程序设计自学:添加图标资源
#include <windows.h> #include "resource.h" LRESULT CALLBACK MyWndProc( HWND hwnd, // ...
- windows程序设计笔记
2014.05.06 新建一个visual C++ -- 常规 -- 空白 的项目,用.c后缀名指定这是一个用C语言来写的windows项目.和C语言的hellworld程序做了一个比较,按照wind ...
- 《Windows程序设计第5版》学习进度备忘
书签:另外跳过的内容有待跟进 __________________学习资源: <Windows程序设计第5版珍藏版> __________________知识基础支持: _________ ...
- MFC Windows程序设计源代码免费下载
本人近期在网上找到了<MFC Windows程序设计>第二版的书内程序的源代码,特意上传CSDN上面,供学习MFC的程序猿们免费下载. 源代码下载: http://download.csd ...
- windows 程序设计 SetPolyFillMode关于ALTERNATE、WINDING的详细解释
看windows程序第五章GDI编程部分.一直卡壳在这里了. 下面我来说下自己的想法.看是否对您有帮助. 首先我们来看一个图. SetPolyFillMode(ALTERNATE); // 系统默认 ...
随机推荐
- eclipse 代码提示快捷键 alt+/
eclipse (ALT+/)1.选择Eclipse菜单栏中的Window->preferences: 2.选择General->keys; 3.在右侧中间的窗体中点击word compl ...
- Informatica ODBC的使用
1.在服务器端配置odbc.ini 注意:添加环境变量才能生效 2.测试连通性 3.使用
- K8S进入容器方法
前言 k8s如何进入一个pod里有多个容器的方法 参考地址 https://blog.csdn.net/aa1215018028/article/details/81205691 方法1 kubect ...
- 分布式锁的实现【基于ZooKeeper】
引言 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提 ...
- Web核心之JSP
JSP JSP = HTML + Java + JSP自己的一些语法 JSP也是一个动态网页开发技术. JSP本质 Jsp实际上就是一个Servlet,在jsp被访问时,tomcat会把jsp转换为一 ...
- Apache HttpClient之fluent API的使用
该方法为Apache HttpClient 4.5以上的版本支持,在官网有明确的说明. 对比以前的方式,其优点是代码更简洁,同时为线程安全的.仅举一个最简单的post栗子 JAR包信息: <de ...
- php array_search()函数 语法
php array_search()函数 语法 作用:在数组中搜索某个键值,并返回对应的键名.dd马达生产厂家 语法:array_search(value,array,strict) 参数: 参数 描 ...
- 禁止input输入框输入指定内容
链接: http://blog.csdn.net/xiaoya_syt/article/details/52746598
- CSS入门基础学习一
一.CSS样式 1.什么是CSS: CSS是指层叠样式表(Cascading Style Sheels),CSS通常为CSS样式表或层叠样式表,主要用于设置HTML文本内容,以及版本面的布局等 2.H ...
- [CSP-S模拟测试]:可爱的精灵宝贝(搜索)
题目描述 $Branimirko$是一个对可爱精灵宝贝十分痴迷的玩家.最近,他闲得没事组织了一场捉精灵的游戏.游戏在一条街道上举行,街道上一侧有一排房子,从左到右房子标号由$1$到$n$.刚开始玩家在 ...