c++ - 在 winapi 中选择按钮会导致其他功能中断
问题描述
我正在使用 Win32 API 编写应用程序。布局基本上由一个永远不会改变的左窗口和一个在两个窗口之间变化的右窗口组成。为了控制这种变化,我使用ShowWindow(hWnd, SW_SHOW/SW_HIDE)
.
在左侧窗口中,有一个按钮可以显示一个窗口并隐藏另一个窗口。我也有显示和隐藏窗口的键盘输入。
在我单击按钮之前,键盘功能正常工作。单击按钮后,按键将停止工作。
起初我以为这是因为按钮是不同的窗口;但是,当我尝试在子窗口中捕获键输入时,什么也没有发生。
这是一个最小的可重现示例,它只有一个按钮和一个子窗口。请注意,单击Shift/Tab会导致子窗口出现/消失。单击该按钮会导致孩子消失一次,但它似乎也禁用了键输入。即使在按钮和子项之外单击也不会恢复它们。
问题可能是什么?
//libraries
#pragma comment ("lib", "Comctl32.lib")
#pragma comment ("lib", "d2d1.lib")
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
// C RunTime Header Files
#include <vector>
#include <string>
#define IDS_APP_TITLE 103
#define IDI_PRACTICE 107
#define IDI_SMALL 108
#define IDC_PRACTICE 109
#define IDC_BUTTON 101
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK WndProcChild(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
ATOM MyRegisterClass(HINSTANCE hInstance);
HWND childHWND;
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_PRACTICE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PRACTICE));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProcChild(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hWnd, message, wParam, lParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
HWND button = CreateWindowW(L"button", L"Hide", WS_CHILD | WS_VISIBLE, 100, 100, 200, 100, hWnd, (HMENU)IDC_BUTTON, hInst, nullptr);
break;
}
case WM_COMMAND:
{
int wmld = LOWORD(wParam);
switch (wmld)
{
case IDC_BUTTON:
ShowWindow(childHWND, SW_HIDE);
break;
}
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
switch (wParam)
{
case VK_SHIFT:
ShowWindow(childHWND, SW_HIDE);
break;
case VK_TAB:
ShowWindow(childHWND, SW_SHOW);
break;
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PRACTICE));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(GetStockObject(WHITE_BRUSH));
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_PRACTICE);
wcex.lpszClassName = L"Parent";
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
//Child wnd class
WNDCLASSEXW wcexChild;
wcexChild.cbSize = sizeof(WNDCLASSEX);
wcexChild.style = CS_HREDRAW | CS_VREDRAW;
wcexChild.lpfnWndProc = WndProcChild;
wcexChild.cbClsExtra = 0;
wcexChild.cbWndExtra = 0;
wcexChild.hInstance = hInstance;
wcexChild.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PRACTICE));
wcexChild.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcexChild.hbrBackground = (HBRUSH)(GetStockObject(BLACK_BRUSH));
wcexChild.lpszMenuName = MAKEINTRESOURCEW(IDC_PRACTICE);
wcexChild.lpszClassName = L"Child";
wcexChild.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcexChild) && RegisterClassExW(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(L"Parent", L"PARENT", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);
childHWND = CreateWindowW(L"Child", szTitle, WS_CHILD | WS_VISIBLE,
500, 500, 500, 500, hWnd, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(childHWND, nCmdShow);
UpdateWindow(childHWND);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
解决方案
您正在主窗口的 WndProc 中处理键盘消息,因此您的窗口只有在具有输入焦点时才会接收键盘消息。当您单击按钮时,它会接收输入焦点,因此后续键盘消息将改为发送到按钮的 WndProc。因此,您必须对按钮进行子类化以拦截发送给它的键盘消息,或者在调度它们之前直接在消息循环中处理键盘消息。
推荐阅读
- javascript - 为什么我的代码只在 javascript 中将此值增加 1 次
- c++ - 没有函数模板的实例与参数列表匹配,参数类型为:(std::string, CommandLineArgumentTypes)
- linux - 如果变量不为空,则 Bash 执行代码
- python - 计算列中的时间值
- java - 如何在 android studio 中创建 IC_launcher 矢量文件?
- mysql - 使用 Facebook 登录凭据登录/注册我的应用程序
- python - phyton 的新功能,但我需要在代码中插入此功能
- html - 位置:绝对中断边距左:自动
- python - * 之后的参数必须是可交互的,而不是浮动的
- python - 如何将ICMP数据保存在python变量中