360浏览器屏蔽某网站怎么做,如何注册一家投资公司,网站建设方案的所属行业是,免费铺货诚招代理商前面我们讨论了鼠标的一些基础知识#xff0c;本节我们将通过一些实例来讲解鼠标消息的不同处理方式。
本节必须掌握的知识点#xff1a; 第36练#xff1a;鼠标击中测试1 第37练#xff1a;鼠标击中测试2—增加键盘接口 第38练#xff1a;鼠标击中测试3—子窗口 第39练本节我们将通过一些实例来讲解鼠标消息的不同处理方式。
本节必须掌握的知识点 第36练鼠标击中测试1 第37练鼠标击中测试2—增加键盘接口 第38练鼠标击中测试3—子窗口 第39练鼠标击中测试4—子窗口增加键盘接口 第40练捕获鼠标消息1 第41练捕获鼠标消息2 第42练获取系统配置信息No.2—增加鼠标滚轮
6.4.1 第36练鼠标击中测试1
/*------------------------------------------------------------------
036 WIN32 API 每日一练 第36个例子CHECKER1.C鼠标击中测试1 WM_LBUTTONDOWN:单击鼠标左键消息
(c) www.bcdaren.com, 2020
----------------------------------------------------------------*/
#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 (Checker1) ; …(略) return msg.wParam ;
}
LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)
{ static BOOL fState[DIVISIONS][DIVISIONS];//默认初始化为0 static int cxBlock,cyBlock; HDC hdc; int x,y; PAINTSTRUCT ps; RECT rect; switch (message) { case WM_SIZE: //矩形方块的宽和高为客户区的1/5 cxBlock LOWORD(lParam) / DIVISIONS; cyBlock HIWORD(lParam) / DIVISIONS; return 0; case WM_LBUTTONDOWN: //单击的矩形索引 x LOWORD(lParam) / cxBlock; y HIWORD(lParam) / cyBlock; //如果鼠标击键消息在客户区范围内 if (x DIVISIONS y DIVISIONS) { //点击区域非零作为绘制对角线的判断条件; fState[x][y] ^ 1;//01 状态切换 rect.left x *cxBlock; rect.top y *cyBlock; rect.right (x 1) * cxBlock; rect.bottom (y 1)* cyBlock; //重绘矩形区域 InvalidateRect(hwnd,rect,FALSE); } else //鼠标点击客户区外 MessageBeep(0);//蜂鸣 return 0; case WM_PAINT: hdc BeginPaint(hwnd,ps); //绘制客户区以DIVSIONS为单位的矩形 for (x 0; x DIVISIONS;x) { for (y 0;y DIVISIONS;y) { Rectangle(hdc,x * cxBlock,y * cyBlock, (x 1) * cxBlock,(y 1) * cyBlock); //如果鼠标点击有效区域 if (fState[x][y])//非零表示有效区域 { //矩形区域内绘制对角线 MoveToEx(hdc,x * cxBlock,y * cyBlock,NULL); LineTo(hdc,(x 1) *cxBlock,(y 1) * cyBlock); MoveToEx(hdc, x * cxBlock, (y 1) * cyBlock, NULL); LineTo(hdc, (x 1) *cxBlock, y * cyBlock); } } } EndPaint(hwnd,ps); return 0; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc (hwnd, message, wParam, lParam) ;
}
/*****************************************************************************
WM_LBUTTONDOWN:表示鼠标左键按下事件。在Windows操作系统中消息是用来传递事件和命令的一种机制
每个消息都有一个唯一的标识符。WM_LBUTTONDOWN消息通常在用户按下鼠标左键时触发
它告诉应用程序用户进行了一个鼠标左键按下的操作。应用程序可以根据这个消息来执行相应的操作
例如捕获鼠标坐标执行特定的功能或者进行其他处理。
*/
运行结果 图6-2 鼠标击中测试1 总结
实例CHECKER1.C的窗口过程首先处理WM_SIZE消息的处理以此获取当前窗口客户区宽和高的五分之一。 接着窗口过程处理WM_LBUTTONDOWN消息捕获鼠标左键通过lParam参数获取鼠标点击时的x和y坐标并判断鼠标点击坐标位置是否位于5*5的客户区矩形区域内。如果不在区域内则蜂鸣提示。如果在区域内使用fState[x][y] ^ 1;语句保存01 状态切换并记录所在矩形区域的rect矩形坐标重绘窗口客户区。 然后处理WM_PAINT消息时在窗口客户区内绘制5*5矩形如果fState[x][y]值为1则在rect矩形内绘制对角线。 6.4.2 第37练鼠标击中测试2—增加键盘接口
/*------------------------------------------------------------------
037 WIN32 API 每日一练 第37个例子CHECKER2.C鼠标击中测试2——增加键盘接口 添加键盘消息WM_KEYDOWN处理 GetCursorPos函数 SetCursorPos函数 SendMessage函数 MAKELONG宏 WM_SETCURSOR消息 WM_KILLFOCUS消息 ShowCursor函数
(c) www.bcdaren.com, 2020
----------------------------------------------------------------*/
#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 (Checker2) ; …(略) return msg.wParam ;
}
LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM
wParam,LPARAM lParam)
{ static BOOL fState[DIVISIONS][DIVISIONS]; static int cxBlock,cyBlock; HDC hdc; int x,y; PAINTSTRUCT ps; POINT point; RECT rect; switch (message) { case WM_SIZE: cxBlock LOWORD(lParam) / DIVISIONS; cyBlock HIWORD(lParam) / DIVISIONS; return 0; //鼠标移入窗口的消息当光标进入或离开某个窗口或控件的客户区域时 //Windows 会生成 WM_SETCURSOR 消息并发送给窗口的消息队列 case WM_SETCURSOR: //如果bShow为TRUE则显示计数增加一。如果bShow为FALSE则显示计数减一。 ShowCursor(TRUE);//显示计数1如果安装了鼠标则忽略 return 0;
//当窗口或控件失去焦点时Windows 将生成 WM_KILLFOCUS 消息并发送给窗口消息队列 case WM_KILLFOCUS: ShowCursor(FALSE);//显示计数-1 return 0; case WM_KEYDOWN: //因wParam为虚拟键码lParam为击键的6个字段没鼠标坐标。 GetCursorPos(point);//检索鼠标光标在屏幕坐标中的位置 ScreenToClient(hwnd,point);//将屏幕坐标转换为客户区坐标 x max(0,min(DIVISIONS - 1,point.x / cxBlock));//0~4 y max(0,min(DIVISIONS - 1,point.y / cyBlock)); switch (wParam) { case VK_UP: y--; break; case VK_DOWN: y; break; case VK_LEFT: x--; break; case VK_RIGHT: x; break; case VK_HOME: x y 0; break; case VK_END: x y DIVISIONS - 1; break; case VK_RETURN: case VK_SPACE: //模拟发送鼠标消息 SendMessage(hwnd,WM_LBUTTONDOWN,MK_LBUTTON, MAKELONG(x * cxBlock,y * cyBlock));//宏置lParam参数高字和低字 break; } //x原区间为[04]5后移到[5,9]区间取模防止x--后出现负数区间。 x (x DIVISIONS) % DIVISIONS; y (y DIVISIONS) % DIVISIONS; //设置鼠标位置到矩形中央位置 point.x x * cxBlock cxBlock / 2; point.y y * cyBlock cyBlock / 2; //客户区坐标转屏幕坐标并设置鼠标位置 ClientToScreen(hwnd,point); SetCursorPos(point.x,point.y); return 0; case WM_LBUTTONDOWN: x LOWORD(lParam) / cxBlock; y HIWORD(lParam) / cyBlock; //如果鼠标击键消息在客户区范围内 if (x DIVISIONS y DIVISIONS) { fState[x][y] ^ 1;//点击区域绘制对角线的判断条件 rect.left x *cxBlock; rect.top y *cyBlock; rect.right (x 1) * cxBlock; rect.bottom (y 1)* cyBlock; //重绘矩形区域 InvalidateRect(hwnd,rect,FALSE); } else //鼠标点击客户区外 MessageBeep(0);//蜂鸣 return 0; case WM_PAINT: hdc BeginPaint(hwnd,ps); //绘制客户区以DIVSIONS为单位的矩形 for (x 0; x DIVISIONS;x) { for (y 0;y DIVISIONS;y) { Rectangle(hdc,x * cxBlock,y * cyBlock, (x 1) * cxBlock,(y 1) * cyBlock); //如果鼠标点击有效区域 if (fState[x][y])//非零表示有效区域 { //矩形区域内绘制对角线 MoveToEx(hdc,x * cxBlock,y * cyBlock,NULL); LineTo(hdc,(x 1) *cxBlock,(y 1) * cyBlock); MoveToEx(hdc, x * cxBlock, (y 1) * cyBlock, NULL); LineTo(hdc, (x 1) *cxBlock, y * cyBlock); } } } EndPaint(hwnd,ps); return 0; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc (hwnd, message, wParam, lParam) ;
}
/****************************************************************************
GetCursorPos函数检索鼠标光标在屏幕坐标中的位置
BOOL GetCursorPos( LPPOINT lpPoint //指向接收光标的屏幕坐标的POINT结构的指针。
);
*****************************************************************************
SetCursorPos函数将光标移动到指定的屏幕坐标
BOOL SetCursorPos( int X, int Y
);
*****************************************************************************
SendMessage函数将指定的消息发送到一个或多个窗口。
LRESULT SendMessage( HWND hWnd, // UINT Msg, //WM_LBUTTONDOWN WPARAM wParam,//MK_LBUTTON LPARAM lParam//MAKELONG(x * cxBlock,y * cyBlock)
);
*****************************************************************************
MAKELONG宏通过串联指定的值来创建LONG值
DWORD MAKELONG( WORD wLow,//新值的低位字。 WORD wHigh//新值的高位字。
);
*****************************************************************************
WM_SETCURSOR消息当光标进入或离开某个窗口或控件的客户区域时
Windows 会生成 WM_SETCURSOR 消息并发送给窗口的消息队列
#define WM_SETCURSOR 0x0020
参数wParam包含光标的窗口的句柄。
lParam
lParam的低位字指定光标位置的命中测试结果。请参阅WM_NCHITTEST的返回值以获取可能的值。
lParam的高位字指定触发此事件的鼠标窗口消息例如WM_MOUSEMOVE。当窗口进入菜单模式时该值为零。
返回值
如果应用程序处理此消息则应返回TRUE停止进一步处理或者返回FALSE继续。
*****************************************************************************
WM_KILLFOCUS消息通知应用程序失去焦点focus。
当窗口或控件失去焦点时Windows 将生成 WM_KILLFOCUS 消息并发送给窗口的消息队列。
应用程序可以通过处理这个消息来响应窗口或控件失去焦点的事件。
*****************************************************************************
ShowCursor函数显示或隐藏光标。
int ShowCursor( BOOL bShow //如果bShow为TRUE则显示计数增加一。如果bShow为FALSE则显示计数减一。
);
返回值
类型int
返回值指定新的显示计数器。
*/
运行结果 图6-3 鼠标击中测试2 总结
实例CHECKER2.C在CHECKER1.C的基础上增加了两个消息的处理和一个键盘接口。 ●WM_SETCURSOR消息WM_SETCURSOR通知应用程序设置光标的外观。当光标进入或离开某个窗口或控件的客户区域时Windows 会生成 WM_SETCURSOR 消息并发送给窗口的消息队列。窗口过程接到WM_SETCURSOR消息时执行ShowCursor(TRUE);语句将鼠标显示计数加一鼠标显示计数为0时隐藏鼠标。
应用程序可以通过处理这个消息来决定在特定情况下如何设置光标的外观。
WM_SETCURSOR 消息的处理通常涉及以下几个步骤
1应用程序接收到 WM_SETCURSOR 消息并确定光标所在的窗口或控件。
2应用程序确定当前光标所处位置的特定情况例如是否在客户区域、非客户区域或控件的边界上。
3应用程序根据特定情况选择合适的光标形状并使用系统函数如 SetCursor设置光标的外观。
通过处理 WM_SETCURSOR 消息应用程序可以实现自定义的光标行为例如根据不同的控件或窗口状态显示不同的光标形状。
需要注意的是WM_SETCURSOR 消息通常与鼠标移动事件相关联。在处理 WM_SETCURSOR 消息时应用程序通常还需要处理与鼠标移动相关的消息如 WM_MOUSEMOVE。 ●WM_KILLFOCUS消息通知应用程序失去焦点focus。当窗口或控件失去焦点时Windows 将生成 WM_KILLFOCUS 消息并发送给窗口的消息队列。应用程序可以通过处理这个消息来响应窗口或控件失去焦点的事件。窗口过程接到WM_KILLFOCUS消息时执行ShowCursor(FALSE);语句将鼠标显示计数减一鼠标显示计数为0时隐藏鼠标。
失去焦点意味着窗口或控件不再是当前接收用户输入的对象。这可能发生在用户将焦点移动到另一个窗口、将焦点转移到桌面或切换到另一个应用程序时。
在处理 WM_KILLFOCUS 消息时应用程序可以执行特定的操作如保存当前输入状态、更新界面或执行其他相关的处理逻辑。
需要注意的是WM_KILLFOCUS 消息是与获得焦点的消息 WM_SETFOCUS 相对应的。当窗口或控件获得焦点时将生成 WM_SETFOCUS 消息。通过处理这两个消息应用程序可以跟踪焦点的变化并作出相应的响应。 ●WM_KEYDOWN消息实例CHECKER2.C通过处理WM_KEYDOWN消息为实例增加一个键盘接口以此支持用户通过键盘上下左右方向键和HOME、END键在25个矩形内移动鼠标指针通过空格和回车键模拟点击鼠标左键。 窗口过程处理WM_KEYDOWN消息时首先调用GetCursorPos函数获取鼠标在屏幕上的坐标然后调用ScreenToClient函数将屏幕坐标转换为客户区坐标。 【注意】通过使用min和max宏将x和y坐标值锁定在0~4之间。 接着通过WM_KEYDOWN消息的wParam参数判断按下了哪个键盘按键。 如果是上下左右方向键则分别将x和y坐标值加一或减一。 如果是HOME键则xy0; 如果是END键则x y DIVISIONS - 1; 如果是空格或回车键则调用SendMessage函数发送一个鼠标WM_LBUTTONDOW消息wParam参数为鼠标左键虚拟键码MK_LBUTTONlParam参数为x和y坐标值使用MAKELONG宏置lParam参数的高字和低字。 最后将x和y坐标置于矩形中心位置并调用ClientToScreen函数将坐标转换为屏幕坐标然后调用SetCursorPos函数将其设置为鼠标坐标。 6.4.3 第38练鼠标击中测试3—子窗口
/*------------------------------------------------------------------
038 WIN32 API 每日一练 第38个例子CHECKER3.C鼠标击中测试3——子窗口 同时注册主窗口与子窗口 子窗口的预留空间 子窗口IDwndclass.lpszMenuName GetWindowLong函数 MoveWindow函数 SetWindowLong函数
(c) www.bcdaren.com, 2020
----------------------------------------------------------------*/
#include windows.h
#define DIVISIONS 5 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //主窗口过程
LRESULT CALLBACK ChildWndProc(HWND, UINT, WPARAM, LPARAM); //子窗口的窗口过程
TCHAR szChildClass[] TEXT(Checker_Child); //须定义为全局变量因为WinMain和WndProc中都要用到。
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{ static TCHAR szAppName[] TEXT(Checker3); …(略) //注册子窗口类 wndclass.cbWndExtra sizeof(long);//保留额外4个字节空间 wndclass.lpszClassName szChildClass; wndclass.hIcon NULL; wndclass.lpfnWndProc ChildWndProc; RegisterClass(wndclass); …(略) return msg.wParam;
}
//主窗口过程
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{ static HWND hwndChild[DIVISIONS][DIVISIONS]; int cxBlock,cyBlock,x,y; switch (message) { //获取主窗口进程句柄hInstance的三种方法 //1、hInstance设置为全局变量 //2、(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE); //3、WM_CREATE消息的(CREATESTRUCTA)lParam-hInstance case WM_CREATE: //创建25个子窗口 for (x 0;x DIVISIONS;x) { for (y 0; y DIVISIONS;y) { hwndChild[x][y] CreateWindow(szChildClass,NULL,
WS_CHILDWINDOW | WS_VISIBLE,//没WS_VISIBLE需要调用ShowWindow 0,0,0,0, hwnd,(HMENU)((y 8) | x),//菜单句柄子ID作为子窗口的唯一标识 (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),//获得hInstance NULL); } } return 0; case WM_SIZE: cxBlock LOWORD(lParam) / DIVISIONS; cyBlock HIWORD(lParam) / DIVISIONS; for (x 0;x DIVISIONS;x) { for (y 0;y DIVISIONS;y) { //更改子窗口的尺寸 MoveWindow(hwndChild[x][y],x * cxBlock,y * cyBlock, cxBlock,cyBlock,TRUE); } } return 0; case WM_LBUTTONDOWN: MessageBeep(0);//有效区外点击鼠标左键蜂鸣 return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd,message,wParam,lParam);
}
//子窗口过程
LRESULT CALLBACK ChildWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{ HDC hdc ; PAINTSTRUCT ps ; RECT rect ; switch (message) { case WM_CREATE : //wndclass.cbWndExtra sizeof(long);//给子窗口预留4个字节空间保存信息 //更改指定窗口的扩展风格、窗口过程地址或用户数据
// on/off flag 子窗口额外4个字节存储空间中保存一个0作为标记值 SetWindowLong (hwnd, 0, 0) ; return 0 ; case WM_LBUTTONDOWN :
//鼠标点击后将将额外存储空间内的0或1进行交替转换 SetWindowLong (hwnd, 0, 1 ^ GetWindowLong (hwnd, 0)) ; InvalidateRect (hwnd, NULL, FALSE) ; //重绘窗口 return 0 ; case WM_PAINT : hdc BeginPaint(hwnd, ps); GetClientRect(hwnd, rect); Rectangle(hdc, 0, 0, rect.right, rect.bottom); if (GetWindowLong(hwnd, 0))//检索有关指定窗口的信息返回值0表示失败 { //画对角线 MoveToEx(hdc, 0, 0, NULL); LineTo(hdc, rect.right, rect.bottom); MoveToEx(hdc, 0, rect.bottom, NULL); LineTo(hdc, rect.right, 0); } EndPaint(hwnd, ps); return 0; } return DefWindowProc (hwnd, message, wParam, lParam) ;
}
/***************************************************************************
MoveWindow函数
更改指定窗口的位置和尺寸。对于顶级窗口位置和尺寸是相对于屏幕的左上角的。
对于子窗口它们相对于父窗口客户区的左上角。
BOOL MoveWindow( HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint//TRUE重绘FALSE
);
***************************************************************************
GetWindowLong函数用于获取窗口属性的函数它可以用来检索指定窗口的扩展风格、窗口样式、窗口过程地址或用户数据。
LONG GetWindowLongA( HWND hWnd,// 要获取属性的窗口句柄。 int nIndex//若指定值大于0返回窗口内存中指定偏移量的32位值。
);
***************************************************************************
SetWindowLong函数改指定窗口的属性。该函数还将指定偏移量的32位长值设置到额外的窗口存储器中。
LONG SetWindowLongA( HWND hWnd, //窗口句柄 int nIndex, //从零开始的要设置值的偏移量。 LONG dwNewLong//替换值。
);
*/
运行结果 图6-4 鼠标击中测试3 总结 实例38和39是通过在窗口客户区绘制25个矩形由主窗口过程负责捕获鼠标左键和键盘消息并绘制矩形对角线。而实例CHECKER3.C则是在窗口客户区绘制了25个子窗口由子窗口过程负责捕获鼠标左键消息并绘制子窗口客户区对角线。 ●首先我们来看主窗口过程 主窗口过程处理WM_CREATE消息时调用CreateWindow绘制25个子窗口子窗口初始尺寸为0。子窗口的标识符为菜单项ID。
然后在WM_SIZE消息中调用MoveWindow函数更改子窗口尺寸。
如果主窗口接到WM_LBUTTONDOWN消息时调用MessageBeep函数蜂鸣示警表示鼠标点击位置落在了主窗口内。 ●再看子窗口过程 子窗口过程处理WM_CREATE消息时调用SetWindowLong函数将窗口预留的4个字节存储空间标记值置0主程序注册子窗口类时初始值为空。
接着在处理WM_LBUTTONDOWN消息时先调用GetWindowLong函数获取窗口额外存储空间的值并与常量值1进行异或运算在0和1之间较替切换然后调用SetWindowLong函数将切换后的值置于窗口额外存储空间。
最后在处理WM_PAINT消息时依据窗口额外存储空间的值绘制客户区对角线。
●SetWindowLong函数用于修改窗口属性的函数它可以用来更改指定窗口的扩展风格、窗口过程地址或用户数据。 在较新的 Windows 版本中推荐使用 SetWindowLongPtr 函数来替代 SetWindowLong特别是在编写 64 位应用程序时以支持更大范围的窗口句柄。SetWindowLongPtr 函数的功能与 SetWindowLong 类似但接受一个 LONG_PTR 参数可以处理 32 位和 64 位窗口句柄。以下是 SetWindowLongPtr 的函数原型
LONG_PTR SetWindowLongPtr( HWND hWnd, int nIndex, LONG_PTR dwNewLong
);
其中参数说明如下
hWnd要修改属性的窗口句柄。
nIndex要修改的属性索引。可以是以下常量之一
GWL_EXSTYLE用于修改窗口的扩展风格。
GWL_STYLE用于修改窗口的样式。
GWL_WNDPROC用于修改窗口过程地址。
GWL_HINSTANCE用于修改窗口实例句柄。
GWL_USERDATA用于修改窗口的用户数据。
dwNewLong新的属性值。
SetWindowLongPtr 函数返回被修改属性的旧值可以在需要时进行保存或进一步处理。
需要注意的是修改窗口属性可能会对窗口的行为和外观产生重要影响因此在使用 SetWindowLongPtr 函数时应谨慎并根据具体需求和文档准确理解每个属性的含义和影响。
●GetWindowLong函数用于获取窗口属性的函数它可以用来检索指定窗口的扩展风格、窗口样式、窗口过程地址或用户数据。
在较新的 Windows 版本中推荐使用 GetWindowLongPtr 函数来替代 GetWindowLong特别是在编写 64 位应用程序时以支持更大范围的窗口句柄。GetWindowLongPtr 函数的功能与 GetWindowLong 类似但接受一个 LONG_PTR 参数可以处理 32 位和 64 位窗口句柄。以下是 GetWindowLongPtr 的函数原型
LONG_PTR GetWindowLongPtr( HWND hWnd, int nIndex
);
其中参数说明如下
hWnd要获取属性的窗口句柄。
nIndex要获取的属性索引。可以是以下常量之一
GWL_EXSTYLE用于获取窗口的扩展风格。
GWL_STYLE用于获取窗口的样式。
GWL_WNDPROC用于获取窗口过程地址。
GWL_HINSTANCE用于获取窗口实例句柄。
GWL_USERDATA用于获取窗口的用户数据。
GetWindowLongPtr 函数返回对应属性的值可以根据需要进一步处理或使用。
需要注意的是获取窗口属性可以用于了解窗口的当前状态和配置但在修改窗口属性之前应该仔细考虑可能的影响和限制。 6.4.4 第39练鼠标击中测试4—子窗口增加键盘接口
/*------------------------------------------------------------------
039 WIN32 API 每日一练 第39个例子CHECKER4.C鼠标击中测试4——子窗口增加键盘接口 WM_SETFOCUS消息 WM_KILLFOCUS消息 SetFocus函数 GetDlgItem函数 GetParent函数
(c) www.bcdaren.com, 2020
----------------------------------------------------------------*/
#include windows.h
#define DIVISIONS 5 LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
LRESULT CALLBACK ChildWndProc (HWND, UINT, WPARAM, LPARAM) ;
int idFocus 0 ; //焦点,当前选中的矩形用子窗口ID来标识
TCHAR szChildClass[] TEXT (Checker4_Child) ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{ static TCHAR szAppName[] TEXT(Checker4); …(略) return msg.wParam;
}
//主窗口过程
LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)
{ static HWND hwndChild[DIVISIONS][DIVISIONS] ; int cxBlock, cyBlock, x, y ; switch (message) { case WM_CREATE : for (x 0; x DIVISIONS; x) for (y 0; y DIVISIONS; y) hwndChild[x][y] CreateWindow(szChildClass, NULL, WS_CHILDWINDOW | WS_VISIBLE, 0, 0, 0, 0, hwnd, (HMENU)(y 8 | x), (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE),NULL); return 0; case WM_SIZE : cxBlock LOWORD(lParam) / DIVISIONS; cyBlock HIWORD(lParam) / DIVISIONS; for (x 0; x DIVISIONS; x) for (y 0; y DIVISIONS; y) MoveWindow(hwndChild[x][y], x * cxBlock, y * cyBlock, cxBlock, cyBlock, TRUE); return 0; case WM_LBUTTONDOWN : MessageBeep (0) ; return 0 ; // 将焦点设置为子窗口 case WM_SETFOCUS: //将接收输入焦点的子窗口 ID保存在全局变量idFocus中 SetFocus (GetDlgItem (hwnd, idFocus)) ; //将键盘焦点设置到指定的窗口 return 0 ; // On key-down 消息上会更改焦点窗口 case WM_KEYDOWN: //恢复原值 x idFocus 0xFF; y idFocus 8; switch (wParam) { case VK_UP: y--; break; case VK_DOWN: y; break; case VK_LEFT: x--; break; case VK_RIGHT: x; break; case VK_HOME: x y 0; break; case VK_END: x y DIVISIONS - 1; break; default: return 0;//其它按键不处理直接返回 } x (x DIVISIONS) % DIVISIONS; y (y DIVISIONS) % DIVISIONS; idFocus y 8 | x; SetFocus(GetDlgItem(hwnd, idFocus));//将键盘焦点设置到指定的子窗口 return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc (hwnd, message, wParam, lParam) ;
}
//子窗口过程
LRESULT CALLBACK ChildWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{ HDC hdc ; PAINTSTRUCT ps ; RECT rect ; switch (message) { case WM_CREATE : SetWindowLong (hwnd, 0, 0) ; // on/off flag 保存在cbWndExtra空间 return 0 ; case WM_KEYDOWN: // 将大多数按键发送到父窗口 if (wParam ! VK_RETURN wParam ! VK_SPACE) { //回车空格键除外的消息返回给父窗口 SendMessage (GetParent (hwnd), message, wParam, lParam) ; return 0 ; } //return 0; // 通过翻转来切换正方形 //回车空格等同于鼠标左键 case WM_LBUTTONDOWN : SetWindowLong(hwnd, 0, 1 ^ GetWindowLong(hwnd, 0)); SetFocus(hwnd);//设置输入焦点 InvalidateRect(hwnd, NULL, FALSE);//使窗口无效以便重新绘制 return 0; case WM_SETFOCUS: //获得键盘焦点消息 idFocus GetWindowLong (hwnd, GWL_ID) ; //获取焦点窗口ID // 继续执行 case WM_KILLFOCUS: //在失去键盘焦点之前立即发送到窗口 InvalidateRect (hwnd, NULL, TRUE) ; return 0 ; case WM_PAINT : //子窗口处理空格和回车消息 hdc BeginPaint (hwnd, ps) ; GetClientRect (hwnd, rect) ; Rectangle (hdc, 0, 0, rect.right, rect.bottom) ; // 绘制对角线 if (GetWindowLong (hwnd, 0)) { MoveToEx(hdc, 0, 0, NULL); LineTo(hdc, rect.right, rect.bottom); MoveToEx(hdc, 0, rect.bottom, NULL); LineTo(hdc, rect.right, 0); } // 绘制焦点矩形--用虚线框表示焦点窗口 if (hwnd GetFocus ()) { rect.left rect.right / 10; rect.right - rect.left; rect.top rect.bottom / 10; rect.bottom - rect.top; SelectObject(hdc, GetStockObject(NULL_BRUSH)); SelectObject(hdc, CreatePen(PS_DASHDOT, 0, 0));//虚线画笔 Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom); DeleteObject(SelectObject(hdc, GetStockObject (BLACK_PEN))); } EndPaint (hwnd, ps) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ;
}
/**************************************************************************
WM_SETFOCUS消息获得键盘焦点后发送到窗口
**************************************************************************
WM_KILLFOCUS消息在失去键盘焦点之前立即发送到窗口
**************************************************************************
SetFocus函数对指定的窗口设置键盘焦点
HWND SetFocus( HWND hWnd
);
**************************************************************************
GetDlgItem函数在指定的对话框中检索控件的句柄
HWND GetDlgItem( HWND hDlg, int nIDDlgItem//要检索的控件的标识符
);
**************************************************************************
GetParent函数检索指定窗口的父级或所有者的句柄
HWND GetParent( HWND hWnd
);
*/ 运行结果 图6-5 鼠标击中测试4 总结 实例CHECKER4.C在CHECKER3.C的基础上增加了键盘接口。这里了的关键是焦点窗口在主窗口与子窗口之间的切换。 ●当我们处理鼠标消息时只需要判断鼠标的坐标位置落在哪个窗口客户区内就可以将窗口焦点切换到该窗口客户区。 ●当我们处理键盘消息时键盘消息只能被送入当前具有输入焦点的窗口因此需要我们先转移输入焦点至我们想要获得键盘输入的窗口才可以。 ●主窗口过程 主窗口过程在处理M_SETFOCUS消息时调用GetDlgItem (hwnd, idFocus)获取之前具有输入焦点的子窗口句柄然后再调用SetFocus函数将焦点还给该子窗口。 主窗口过程处理WM_KEYDOWN消息时说明主窗口当前获取了输入焦点否则也不可能获取按键消息。在处理WM_KEYDOWN消息时分别处理上下左右和HOME、END按键重置坐标x和y的值。【注意】重置坐标后还需要调用SetFocus函数再次将输入焦点还给之前具有输入焦点的子窗口。 ●子窗口过程 子窗口过程在处理M_KEYDOWN消息时只负责处理回车和空格键其他按键消息调用SendMessage函数将其返还给主窗口。 如果是回车和空格按键消息或者是WM_LBUTTONDOWN鼠标左键消息则重置窗口额外空间存储的标记值然后调用SetFocus函数让当前窗口获取输入焦点。不要返回接着处理WM_KILLFOCUS消息在当前子窗口失去焦点时重绘子窗口。 ●实例新增两个函数 1GetDlgItem函数在指定的对话框中检索控件的句柄。
GetDlgItem 函数的函数原型
HWND GetDlgItem( HWND hDlg, int nIDDlgItem
);
其中参数说明如下
hDlg对话框的句柄即包含目标控件的对话框窗口。
nIDDlgItem控件的标识符(ID)它是在对话框模板中为每个控件分配的唯一标识符。
GetDlgItem 函数会根据指定的对话框句柄和控件标识符在对话框中查找对应控件的句柄并返回该句柄。
通过获取控件的句柄应用程序可以进一步操作和控制该控件例如修改其属性、获取或设置其文本内容、发送消息给控件等。 2GetParent函数检索指定窗口的父级或所有者的句柄。 GetParent 函数的函数原型
HWND GetParent( HWND hWnd
);
其中参数说明如下
hWnd要获取父窗口句柄的窗口句柄。
GetParent 函数会返回指定窗口的父窗口句柄。父窗口通常是容器窗口包含了子窗口或控件。
通过获取父窗口句柄应用程序可以对父窗口及其子窗口进行操作和控制例如修改父窗口的属性、发送消息给父窗口或子窗口等。
需要注意的是父窗口并不一定是直接的父子关系可能存在多层嵌套的窗口结构。在多层嵌套的情况下GetParent 函数仅返回指定窗口的直接父窗口句柄。
另外顶级窗口没有父窗口的窗口的父窗口句柄通常是桌面窗口的句柄。 6.4.5 第40练捕获鼠标消息1
/*------------------------------------------------------------------
040 WIN32 API 每日一练 第40个例子BLOKOUT1.C捕获鼠标消息1 SetROP2函数 SetCursor函数
缺陷无法捕捉客户区外的鼠标消息
(c) www.bcdaren.com, 2020
----------------------------------------------------------------*/
#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(BlokOut1); …(略) return msg.wParam;
}
//绘制矩形图
void DrawBoxOutline (HWND hwnd, POINT ptBeg, POINT ptEnd)
{ HDC hdc; hdc GetDC(hwnd); SetROP2(hdc, R2_NOT);//颜色取反。可删除旧的边框新边框颜色为黑色。 SelectObject(hdc, GetStockObject(NULL_BRUSH));//空笔刷 Rectangle(hdc, ptBeg.x, ptBeg.y, ptEnd.x, ptEnd.y); ReleaseDC(hwnd, hdc);
}
LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam,LPARAM
lParam)
{ static BOOL fBlocking, fValidBox ; static POINT ptBeg, ptEnd, ptBoxBeg, ptBoxEnd ; HDC hdc ; PAINTSTRUCT ps ; switch (message) { case WM_LBUTTONDOWN : //获取鼠标位置信息 ptBeg.x ptEnd.x LOWORD (lParam) ; ptBeg.y ptEnd.y HIWORD (lParam) ; //绘制矩形(0000) DrawBoxOutline (hwnd, ptBeg, ptEnd) ; //捕获鼠标设置鼠标形状 SetCursor (LoadCursor (NULL, IDC_CROSS)) ; //标记值 fBlocking TRUE ; //阻塞 return 0 ; case WM_MOUSEMOVE : if (fBlocking) { //捕获鼠标设置鼠标形状 SetCursor(LoadCursor(NULL, IDC_CROSS)); //删除旧边框颜色取反 DrawBoxOutline(hwnd, ptBeg, ptEnd); //获取鼠标位置信息 ptEnd.x LOWORD(lParam); ptEnd.y HIWORD(lParam); //绘制新边框颜色再次取反 DrawBoxOutline(hwnd, ptBeg, ptEnd); } return 0 ; case WM_LBUTTONUP : //释放鼠标左键 if (fBlocking) //按下鼠标左键并绘制矩形 { //删除旧矩形 DrawBoxOutline(hwnd, ptBeg, ptEnd); //获取鼠标位置信息 ptBoxBeg ptBeg; ptBoxEnd.x LOWORD(lParam); ptBoxEnd.y HIWORD(lParam); //捕获鼠标设置鼠标位图 SetCursor(LoadCursor(NULL, IDC_ARROW)); fBlocking FALSE;//标记没有按下鼠标左键 fValidBox TRUE;//标记已释放鼠标左键 //重绘窗口客户区 InvalidateRect(hwnd, NULL, TRUE); } return 0; case WM_CHAR : // Escape键 fBlocking否则将不断切换显示与隐藏边框 if (fBlocking (wParam \x1B)) { DrawBoxOutline(hwnd, ptBeg, ptEnd); SetCursor(LoadCursor(NULL, IDC_ARROW)); fBlocking FALSE; } return 0 ; case WM_PAINT : hdc BeginPaint (hwnd, ps) ; if (fValidBox) //捕获到WM_LBUTTONUP消息时 { //填充矩形 SelectObject(hdc, GetStockObject(BLACK_BRUSH)); Rectangle(hdc, ptBoxBeg.x, ptBoxBeg.y, ptBoxEnd.x, ptBoxEnd.y); } EndPaint (hwnd, ps) ; return 0 ; case WM_DESTROY : PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ;
}
/****************************************************************************
SetROP2函数设置当前的前景混合模式。
GDI使用前景混合模式将笔和填充对象的内部与屏幕上已经存在的颜色结合起来。
前景混合模式定义如何将画笔或笔中的颜色与现有图像中的颜色进行组合。
int SetROP2( HDC hdc,//设备上下文的句柄 int rop2//混合模式。R2_NOT颜色取反
);
****************************************************************************
SetCursor函数设置鼠标位图。
HCURSOR SetCursor( HCURSOR hCursor //光标句柄
);
光标的句柄。游标必须已经由CreateCursor函数创建或已由LoadCursor或LoadImage函数加载。
如果此参数为NULL则将光标从屏幕上移开。
*/ 运行结果 图6-6 捕获鼠标消息1 总结 1实例BLOKOUT1.C自定义了一个绘图函数DrawBoxOutline。先将绘图二元光栅操作模式设置为颜色取反然后选入空画刷填充矩形背景调用Rectangle绘制矩形。 2在窗口过程中首先处理WM_LBUTTONDOWN消息由消息参数lParam获取鼠标位置接着调用DrawBoxOutline函数绘制矩形并调用SetCursor将鼠标位图设置为十字形。将标记变量fBlocking设为TRUE表示已按下鼠标左键并绘制矩形。 3接着处理鼠标移动消息WM_MOUSEMOVE。调用SetCursor捕获鼠标并将鼠标位图设置为十字。通过lParam参数获取移动鼠标的当前坐标。 【注意】这里两次调用DrawBoxOutline函数第一次擦掉原来的矩形第二次绘制新坐标位置的矩形。 4接着处理WM_LBUTTONUP消息当释放鼠标左键时调用DrawBoxOutline函数删除旧的矩形。通过lParam参数获取当前鼠标坐标信息。调用SetCursor函数捕获鼠标并将鼠标位图重新设置为箭头。接着把标记变量fBlocking设为FALSE表示没有按下鼠标左键把标记变量fValidBox设置为TRUE表示已释放鼠标左键。最后调用InvalidateRect重绘窗口客户区并擦除背景。 5处理WM_CHAR消息时当按下ESC键并且按下鼠标左键时调用DrawBoxOutline函数擦除矩形并将鼠标位图改为箭头。标记变量fBlocking设为FALSE。 6处理WM_PAINT消息当捕获释放鼠标左键时选入黑色画刷填充由Rectangle绘制的矩形。 【注意】该实例无法捕捉窗口客户区之外的鼠标因此当鼠标移动到窗口客户区之外时无法正常绘制矩形。我们将在下一个实例中修正。 6.4.6 第41练捕获鼠标消息2
/*------------------------------------------------------------------
041 WIN32 API 每日一练 第41个例子BLOKOUT2.C捕获鼠标消息2 SetCapture函数 ReleaseCapture函数
修正无法捕捉客户区外的鼠标消息
(c) www.bcdaren.com, 2020
----------------------------------------------------------------*/
#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(BlokOut2); …(略) return msg.wParam;
}
//绘图函数
void DrawBoxOutline (HWND hwnd, POINT ptBeg, POINT ptEnd)
{ …(略)
}
LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)
{ static BOOL fBlocking, fValidBox ; static POINT ptBeg, ptEnd, ptBoxBeg, ptBoxEnd ; HDC hdc ; PAINTSTRUCT ps ; switch (message) { case WM_LBUTTONDOWN : ptBeg.x ptEnd.x LOWORD(lParam); ptBeg.y ptEnd.y HIWORD(lParam); DrawBoxOutline(hwnd, ptBeg, ptEnd); //新增代码1 SetCapture(hwnd);//将鼠标捕获设置为属于当前线程的指定窗口 SetCursor(LoadCursor(NULL, IDC_CROSS)); fBlocking TRUE; return 0; case WM_MOUSEMOVE : …(略) return 0; case WM_LBUTTONUP : if (fBlocking) { DrawBoxOutline(hwnd, ptBeg, ptEnd); ptBoxBeg ptBeg; ptBoxEnd.x LOWORD(lParam); ptBoxEnd.y HIWORD(lParam); //新增代码2
//从当前线程的窗口中释放鼠标捕获并恢复正常的鼠标输入处理 ReleaseCapture(); SetCursor(LoadCursor(NULL, IDC_ARROW)); fBlocking FALSE; fValidBox TRUE; InvalidateRect(hwnd, NULL, TRUE); } return 0; case WM_CHAR : if (fBlocking (wParam \x1B)) // i.e., Escape { DrawBoxOutline(hwnd, ptBeg, ptEnd); //新增代码3
//从当前线程的窗口中释放鼠标捕获并恢复正常的鼠标输入处理 ReleaseCapture(); SetCursor(LoadCursor(NULL, IDC_ARROW)); fBlocking FALSE; } return 0 ; case WM_PAINT : hdc BeginPaint(hwnd, ps); …(略)
EndPaint(hwnd, ps); return 0; case WM_DESTROY : PostQuitMessage(0); return 0; } return DefWindowProc (hwnd, message, wParam, lParam) ;
}
/******************************************************************************
SetCapture函数将鼠标捕获设置为属于当前线程的指定窗口。
当鼠标悬停在捕获窗口上方时或者当鼠标悬停在捕获窗口上方
按下鼠标按钮时SetCapture捕获鼠标输入。一次只能捕获一个窗口。
如果鼠标光标位于另一个线程创建的窗口上则仅当按下鼠标按钮时系统才会将鼠标输入定向到指定的窗口。
HWND SetCapture( HWND hWnd //当前线程中要捕获鼠标的窗口的句柄。
);
*******************************************************************************
ReleaseCapture函数从当前线程的窗口中释放鼠标捕获并恢复正常的鼠标输入处理。
捕获光标的窗口将接收所有鼠标输入而与光标的位置无关除非在光标热点位于另一个线程的窗口中时单击鼠标按钮。
BOOL ReleaseCapture();
*/ 运行结果 图6-7 捕获鼠标消息2 总结 实例BLOKOUT2.C新增了三处代码 1处理WM_LBUTTONDOWN消息时调用SetCapture函数。
SetCapture(hwnd);//将鼠标捕获设置为属于当前线程的指定窗口 2处理WM_LBUTTONUP消息时调用函数ReleaseCapture。
ReleaseCapture();//从当前线程的窗口中释放鼠标捕获并恢复正常的鼠标输入处理 3处理WM_CHAR消息时调用函数ReleaseCapture。
ReleaseCapture();//从当前线程的窗口中释放鼠标捕获并恢复正常的鼠标输入处理 这样窗口就可以捕捉和释放客户区之外的鼠标坐标位置信息即使鼠标移动到客户区之外也可以正常绘制矩形了。 SetCapture函数用于设置指定窗口捕获鼠标输入。以下是 SetCapture 函数的函数原型
HWND SetCapture( HWND hWnd //要捕获鼠标输入的窗口句柄
);
4SetCapture 函数用于将鼠标输入的捕获设置到指定的窗口。一旦窗口捕获了鼠标输入无论鼠标是否在窗口的客户区内窗口都将收到鼠标消息。通常情况下只有在特定的情况下才需要使用 SetCapture 函数。
以下是一些常见的使用情况
实现拖拽操作在开始拖拽操作时调用 SetCapture 函数将鼠标输入捕获到拖拽的窗口这样即使鼠标移出窗口的客户区窗口也能持续接收鼠标消息直到松开鼠标按钮。
自定义鼠标操作在某些特殊的应用场景中可能需要自定义鼠标操作例如绘制自定义的鼠标形状或处理特定的鼠标事件。通过调用 SetCapture 函数可以捕获鼠标输入并自行处理相应的鼠标消息。
需要注意的是使用 SetCapture 函数后必须在适当的时候调用 ReleaseCapture 函数来释放对鼠标输入的捕获。这样可以确保在不需要捕获鼠标输入时将鼠标输入的控制权交还给系统。 5ReleaseCapture 函数用于释放对鼠标输入的捕获。以下是 ReleaseCapture 函数的函数原型
BOOL ReleaseCapture();
ReleaseCapture 函数用于释放先前使用 SetCapture 函数设置的鼠标输入捕获。一旦调用 ReleaseCapture 函数窗口将不再捕获鼠标输入鼠标输入将返回给系统。
通常情况下与 SetCapture 函数配对使用在不需要继续捕获鼠标输入时调用 ReleaseCapture 函数。 6.4.7 第42练获取系统信息—增加鼠标滚轮
/*------------------------------------------------------------------
042 WIN32 API 每日一练 第42个例子SYSMETS.C获取系统配置信息No.2—增加鼠标滚轮 WM_SETTINGCHANGE消息 WM_MOUSEWHEEL消息 SystemParametersInfo函数
(c) www.bcdaren.com, 2020
----------------------------------------------------------------*/
#include windows.h
#include sysmets.h LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{ static TCHAR szAppName[] TEXT(SysMets); …(略) return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{ static int cxChar, cxCaps, cyChar, cxClient, cyClient, iMaxWidth; HDC hdc; int i, x, y, iVertPos, iHorzPos, iPaintBeg, iPaintEnd; PAINTSTRUCT ps; SCROLLINFO si; TCHAR szBuffer[10]; TEXTMETRIC tm; ULONG ulScrollLines;//鼠标滚动行数 static int iDeltaPerLine, iAccumDelta; //每行增量和累积增量 switch (message) { case WM_CREATE: …(略) return 0;
//鼠标滚轮消息在用户操作鼠标滚轮时发送给窗口以通知窗口发生了滚轮滚动事件 //wParam //高序位字指示滑轮旋转的距离以滑轮增量的倍数或间隔表示即120。 //正值表示滚轮向前旋转远离用户; 负值表示滑轮向后旋转朝向用户。 //低序位字指示各种虚拟键是否已关闭。 //lParam //低序位字指定指针的 x 坐标相对于屏幕的左上角。 //高序位字指定指针的 y 坐标相对于屏幕左上角。 case WM_MOUSEWHEEL: if (iDeltaPerLine 0) break; iAccumDelta (short)HIWORD(wParam); //累积增量±120 //通过该循环将iAccumDelta由120变为0 while (iAccumDelta iDeltaPerLine) { SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0); iAccumDelta - iDeltaPerLine; } //通过该循环将iAccumDelta由-120变为0 while (iAccumDelta -iDeltaPerLine) // { SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0); iAccumDelta iDeltaPerLine; } return 0; case WM_KEYDOWN: //处理键盘消息 …(略) return 0; case WM_SIZE: …(略) return 0; case WM_VSCROLL: …(略) return 0; case WM_HSCROLL: …(略) return 0; case WM_PAINT: hdc BeginPaint(hwnd, ps); …(略) EndPaint(hwnd, ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam);
}
/******************************************************************************
WM_SETTINGCHANGE消息:当SystemParametersInfo函数更改系统范围的设置或更改策略设置时发送到所有顶级窗口的消息。
更改系统参数后应用程序应将WM_SETTINGCHANGE发送给所有顶级窗口。此消息不能直接发送到窗口。
WM_SETTINGCHANGE消息发送到所有顶级窗口请使用SendMessageTimeout函数并将hwnd参数设置为HWND_BROADCAST。
窗口通过其WindowProc函数接收此消息。
*******************************************************************************
WM_MOUSEWHEEL消息:旋转鼠标滚轮时发送到焦点窗口。
DefWindowProc会将消息沿父链传播直到找到处理该消息的窗口为止。
消息不应进行内部转发.
窗口通过其WindowProc函数接收此消息。
wParam
高序位字指示滑轮旋转的距离以滑轮增量的倍数或间隔表示即120。
正值表示滚轮向前旋转远离用户;负值表示滑轮向后旋转朝向用户。
低序位字指示各种虚拟键是否已关闭。
lParam
低序位字指定指针的 x 坐标相对于屏幕的左上角。
高序位字指定指针的 y 坐标相对于屏幕左上角。
返回值
如果应用程序处理此消息则它应返回零。
*******************************************************************************
SystemParametersInfo函数:查询或设置系统级参数。
该函数也可以在设置参数中更新用户配置文件这个函数还有很多其它功能比如获取桌面工作区的大小。
BOOL SystemParametersInfoA( UINT uiAction,//要检索或设置的系统范围参数。 UINT uiParam,//参数的用法和格式取决于要查询或设置的系统参数。 PVOID pvParam,//参数的用法和格式取决于要查询或设置的系统参数。 UINT fWinIni//如果正在设置系统参数则指定是否要更新用户配置文件
//如果要更新则是否将WM_SETTINGCHANGE消息广播到所有顶级窗口以将更改通知他们。 //如果您不想更新用户配置文件或广播WM_SETTINGCHANGE消息 //则此参数可以为零也可以为以下值中的一个或多个。
);
*/ 运行结果 图6-8 获取系统信息2 总结 实例SYSMETS.C获取系统配置信息No.2在第三章获取系统配置信息No.1版本的基础上增加了对鼠标滚轮消息的处理 1WM_SETTINGCHANGE消息用于通知应用程序系统设置的更改是由系统发送给顶级窗口Top-level Window以通知它们系统设置的更改例如显示设置、输入设置、语言设置等。
当系统设置发生更改时Windows 将发送 WM_SETTINGCHANGE 消息给所有顶级窗口以便它们可以更新并适应新的设置。应用程序可以通过处理这个消息来获取有关系统设置更改的通知并相应地更新其用户界面或执行其他操作。
以下是 WM_SETTINGCHANGE 消息的消息参数
WM_SETTINGCHANGE WPARAM wParam;
LPARAM lParam;
其中wParam 和 lParam 参数的含义取决于具体的设置更改。通常情况下lParam 参数是一个指向以 NULL 结尾的字符串的指针该字符串包含有关所做更改的信息。应用程序可以通过检查 lParam 参数来确定具体的设置更改类型。
2本实例在处理WM_SETTINGCHANGE消息时先调用SystemParametersInfo函数获取鼠标滚轮每次滚动的行数预设值一般为3。如果每次滚动的行数ulScrollLines为0则iDeltaPerLine 0;每次滚动一行需要0个止动器值。如果每次滚动的行数ulScrollLines为3则iDeltaPerLine 40;每次滚动一行需要40个止动器值。
WM_MOUSEWHEEL 是 Windows 消息中的一个消息代码用于通知应用程序鼠标滚轮的滚动事件。
3WM_MOUSEWHEEL 消息在用户操作鼠标滚轮时发送给窗口以通知窗口发生了滚轮滚动事件。这个消息提供了有关滚轮滚动的信息例如滚动的距离和滚动的方向。
以下是 WM_MOUSEWHEEL 消息的消息参数
WM_MOUSEWHEEL WPARAM wParam; LPARAM lParam;
其中wParam 参数包含了关于滚轮滚动的信息主要包括以下内容
高位字16位表示鼠标滚轮滚动的距离单位为 WHEEL_DELTA通常为 120。正值表示向前滚动负值表示向后滚动。
低位字16位保留未使用。
lParam 参数包含了关于鼠标滚轮滚动事件发生时的鼠标位置信息。
4本实例处理WM_MOUSEWHEEL 消息
当累加增量iAccumDelta等于120时调用SendMessage函数向垂直滚动条发送WM_VSCROLL消息向上滚动一行直至累积增量为0。
当累加增量iAccumDelta等于-120时调用SendMessage函数向垂直滚动条发送WM_VSCROLL消息向下滚动一行直至累积增量为0。