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

もう 1 つの方法は、子ウィンドウのサンプル コードに TranslateAccelerator を使用しないことです。

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

メッセージが mainWidget のものでない場合、メイン ウィジェットのアクセラレータ テーブルを使用してアクセラレータを変換しません。

于 2013-11-22T06:44:08.600 に答える