c++ - 为什么在触发 WM_COMMAND 时 WM_KEYDOWN 不起作用?
问题描述
当我单击客户端窗口中的按钮然后按下向下箭头键时,WM_KEYDOWN 不会发送到我的 Windows 程序,但其他情况始终有效,因此要解决此问题,我必须在客户端窗口外部单击然后单击我的客户端窗口(但不是按钮)然后 WM_KEYDOWN 将起作用,有没有更好的方法来停止我的按钮的焦点?
这是代码:
#include <iostream>
#define _WIN32_WINNT 0x0501
#include <Windows.h>
#include <winuser.h>
#include <vector>
#include<string>
using namespace std;
const char* className = "MyCLASSNAME!";
HWND hButton;
RECT rect;
POINT p = {0, 0};
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
hButton = CreateWindow(TEXT("BUTTON"), TEXT("1"), WS_VISIBLE | WS_CHILD, 8, 41, 50, 50, hWnd, (HMENU)1, NULL, NULL);
break;
case WM_KEYDOWN:
switch (wParam)
{
case VK_DOWN:
if(GetWindowRect(hButton, &rect))
{
POINT p1 = {rect.left, rect.top};
ScreenToClient(hWnd, &p1);
SetWindowPos(hButton, NULL, p1.x, p1.y, rect.right - rect.left + 1, rect.bottom - rect.top + 1, SWP_SHOWWINDOW);
}
break;
}
break;
case WM_LBUTTONDOWN:
GetCursorPos( &p );
GetClientRect(hButton, &rect);
SetWindowPos(hButton, NULL, p.x, p.y - 22, rect.right, rect.bottom, SWP_SHOWWINDOW);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case 1:
break;
}
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
WNDCLASSEXA wc;
HWND hWnd;
MSG msg;
wc.cbClsExtra = 0;
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbWndExtra = 0;
wc.hbrBackground = CreateSolidBrush(RGB(0,0,0));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = className;
wc.lpszMenuName = "MENU!";
wc.style = NULL;
RegisterClassEx(&wc);
hWnd = CreateWindowEx(WS_EX_LAYERED, className, "hello", WS_OVERLAPPEDWINDOW, 0, 0, 500, 500, NULL, NULL, hInstance, NULL);
SetLayeredWindowAttributes(hWnd, 0, 255, LWA_ALPHA);
ShowWindow(hWnd, nShowCmd);
UpdateWindow(hWnd);
while(GetMessage(&msg, hWnd, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
解决方案
原因是当您按下按钮时,您将注意力集中在当前按钮上,因此您的WM_KEYDOWN
消息将发送到该按钮。
所以需要对按钮进行子类化并处理按钮的WM_KEYDOWN
消息。可以参考文档。
这是修改后的示例:
#include <iostream>
#define _WIN32_WINNT 0x0501
#include <Windows.h>
#include <winuser.h>
#include <vector>
#include <string>
#include <CommCtrl.h>
using namespace std;
const char* className = "MyCLASSNAME!";
HWND hWnd;
HWND hButton;
RECT rect;
POINT p = { 0, 0 };
WNDPROC ButtonOldProc;
LRESULT CALLBACK ButtonProcNew(HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (message)
{
case WM_KEYDOWN:
switch (wParam)
{
case VK_DOWN:
if (GetWindowRect(hButton, &rect))
{
POINT p1 = { rect.left, rect.top };
ScreenToClient(hWnd, &p1);
SetWindowPos(hButton, NULL, p1.x, p1.y, rect.right - rect.left + 1, rect.bottom - rect.top + 1, SWP_SHOWWINDOW);
}
break;
}
break;
default:
return DefSubclassProc(hwnd, message, wParam, lParam);
}
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
hButton = CreateWindow(TEXT("BUTTON"), TEXT("1"), WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 8, 41, 50, 50, hWnd, (HMENU)1, NULL, NULL);
SetWindowSubclass(hButton, ButtonProcNew, 0, 0);
break;
case WM_KEYDOWN:
switch (wParam)
{
case VK_DOWN:
if (GetWindowRect(hButton, &rect))
{
POINT p1 = { rect.left, rect.top };
ScreenToClient(hWnd, &p1);
SetWindowPos(hButton, NULL, p1.x, p1.y, rect.right - rect.left + 1, rect.bottom - rect.top + 1, SWP_SHOWWINDOW);
}
break;
}
break;
case WM_LBUTTONDOWN:
GetCursorPos(&p);
GetClientRect(hButton, &rect);
SetWindowPos(hButton, NULL, p.x, p.y - 22, rect.right, rect.bottom, SWP_SHOWWINDOW);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case 1:
break;
}
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
WNDCLASSEXA wc;
MSG msg;
wc.cbClsExtra = 0;
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbWndExtra = 0;
wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = className;
wc.lpszMenuName = "MENU!";
wc.style = NULL;
RegisterClassEx(&wc);
hWnd = CreateWindowEx(WS_EX_LAYERED, className, "hello", WS_OVERLAPPEDWINDOW, 0, 0, 500, 500, NULL, NULL, hInstance, NULL);
SetLayeredWindowAttributes(hWnd, 0, 255, LWA_ALPHA);
ShowWindow(hWnd, nShowCmd);
UpdateWindow(hWnd);
while (GetMessage(&msg, hWnd, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
注意:需要链接 Comctl32.lib
它对我有用:
推荐阅读
- python - 将字符串在 Pandas 数据框中出现的次数附加到另一列
- javascript - 如何在angularjs中使用标签进行搜索
- python-3.x - 未找到 win32gui 模块
- python - 从列表列表创建字典
- mysql - Freeradius 显示不正确的在线用户数与 NAS
- mockito - mockito - 模拟不同包中的受保护方法
- java - 使用 Apache FOP 时波兰语特殊字母不可用
- r - 对 ANN 的输出进行缩放
- javascript - 如何让 react.js 中的 render() 等待我的数组填充来自 xml 的对象
- r - 按大洲列出的国家汇总列表