我使用C和Windows API创建了一个Windows GUI程序,我希望程序能够使用键盘加速器。我已经设置了一些正常工作的加速器,但是当焦点转到程序主窗口的子窗口时,例如列表视图控件或状态栏控件,键盘加速器似乎被转换为WM_COMMAND消息对于子窗口而不是主窗口。因此,当焦点在子控件上时,我将忽略在主窗口的WndProc中处理适当的WM_COMMAND消息。
我该如何解决这个问题?
答案 0 :(得分:3)
我找到了答案。主窗口的子窗口必须是子类,以便键盘加速器生成的WM_COMMAND消息可以被拦截并传递给父窗口。
这涉及将控件的窗口过程更改为其他窗口过程。备用过程通过将它们发送到父窗口来处理应该被截获的消息。还必须将指向原始窗口过程的指针存储在某处,以便控件可以正常运行。
可以使用GWLP_WNDPROC SetWindowLongPtr更改窗口过程。
下面是一个简单的示例,说明如何通过在控件的用户数据值(GWLP_USERDATA)中存储指向原始窗口过程的指针来实现此目的:
更改窗口过程并将原始过程存储在GWLP_USERDATA中的代码:
SetWindowLongPtr( hWnd, GWLP_USERDATA, ( LONG_PTR )SetWindowLongPtr( hWnd, GWLP_WNDPROC, ( LONG_PTR )WndProc ) );
拦截窗口程序:
static LRESULT CALLBACK WndProc( const HWND hWnd, const UINT message, const WPARAM wParam, const LPARAM lParam )
{
switch( message )
{
case WM_COMMAND:
SendMessage( GetParent( hWnd ), message, wParam, lParam );
return 0;
default:
//Assume that GWLP_USERDATA has been set to the original window procedure.
return CallWindowProc( ( WNDPROC )GetWindowLongPtr( hWnd, GWLP_USERDATA ), hWnd, message, wParam, lParam );
}
}
答案 1 :(得分:0)
另一种方法是避免将TranslateAccelerator用于子窗口,示例代码:
if (mainWidget() && msg.hwnd == mainWidget()->hwnd()) {
if (TranslateAccelerator(msg.hwnd, hMainAccelTable, &msg)) {
continue;
}
}
TranslateMessage(&msg);
DispatchMessage(&msg);
如果消息不是mainWidget,我们不会使用主窗口小部件的加速器表来为它加速。