2

我已经使用 C 和 Windows API 创建了一个 Windows GUI 程序,并且我希望该程序利用键盘加速器。我已经设置了一些可以正常工作的加速器,但是当焦点转到我的程序主窗口的子窗口时,例如列表视图控件或状态栏控件,键盘加速器似乎正在转换为 WM_COMMAND 消息对于子窗口而不是主窗口。因此,当焦点位于子控件上时,我在主窗口的 WndProc 中对相应 WM_COMMAND 消息的处理将被忽略。

我应该如何解决这个问题?

4

2 回答 2

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 );
    }
}
于 2009-12-26T09:51:45.787 回答
0

另一种方法是避免对子窗口使用 TranslateAccelerator,示例代码:

if (mainWidget() && msg.hwnd == mainWidget()->hwnd()) {
            if (TranslateAccelerator(msg.hwnd, hMainAccelTable, &msg)) {
                continue;
            }
        }
        TranslateMessage(&msg);
        DispatchMessage(&msg);

如果消息不是主小部件的,我们不使用主小部件的加速器表为它翻译加速器。

于 2013-11-22T06:44:08.600 回答