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); // 系统默认 ...
随机推荐
- mongodb 用户 权限 设置 详解
原文地址:http://blog.51yip.com/nosql/1575.html 我知道的关系型数据库都是有权限控制的,什么用户能访问什么库,什么表,什么用户可以插入,更新,而有的用户只有读取权限 ...
- jenkins解决python不是内部命令
1.在 Windows 提示符下运行是没有问题. 2.把Jenkins项目配置中 python main.py 修改成python可执行文件全路径:D:\Python35\python.exe m ...
- web选择文件夹上传
我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用. 这次项目的需求: 支持大文件的上传和续传,要求续传支持所有浏览器,包括ie6,ie7,i ...
- 实现网页qq在线咨询功能
在自己的网页中实现qq在线咨询,给图片或链接添加地址为:tencent://message/?uin=你的qq号码!就可以了. <a href="tencent://message/? ...
- android设置系统默认开机时间
1.设置RTC时间,该时间是如果RCT时钟断电以后使用的默认时间 Android L之前: \alps\mediatek\custom\[project]\preloader\ inc\cust_rt ...
- What is httpcontext
https://docs.microsoft.com/en-us/dotnet/api/system.web.httpcontext?view=netframework-4.8 Encapsulate ...
- brdd 惰性执行 mapreduce 提取指定类型值 WebUi 作业信息 全局临时视图 pyspark scala spark 安装
[rdd 惰性执行] 为了提高计算效率 spark 采用了哪些机制 1-rdd 基于分布式内存数据集进行运算 2-lazy evaluation :惰性执行,即rdd的变换操作并不是在运行该代码时立 ...
- spring boot创建多模块聚合工程
环境:java1.8,idea 聚合工程优势: 1.统一maven操作.可以在一个maven工程管理多个子工程(每个子工程可单独打包,重启,调试.也可通过聚合工程一起管理). 2.统一管理依赖版本.可 ...
- Dos.Common - 目录、介绍
引言: Dos.Common是一个开发中的常用类库,如HttpHelper.LogHelper.CacheHelper.CookieHelper.MapperHelper等等.与Dos.WeChat. ...
- c++内存布局与c程序的内存布局
c/c++的内存布局:堆,栈,自由存储区(与堆的区别),全局/静态存储区,常量存储区(字符串常量,const常量) http://www.cnblogs.com/QG-whz/p/5060894.ht ...