0

C ++アプリケーション用にGUIを実行しようとしていますが、キー押下イベントに問題があります。基本的に、ボタンをクリックしない限り(メインウィンドウはキーイベントを登録します)、すべてが正常に機能しますが、ボタンをクリックするとすぐにメインウィンドウはフォーカスを失い、キーイベントをキャプチャしなくなります。これはばかげた質問かもしれませんが、私はC++を初めて使用します。これは私が使用しているコードの一部です:

メインウィンドウの作成:

hwnd = CreateWindowEx (
               0,                   /* Extended possibilites for variation */
               szClassName,         /* Classname */
               "Application Name",  /* Title Text */
               WS_OVERLAPPEDWINDOW, /* default window */
               CW_USEDEFAULT,       /* Windows decides the position */
               CW_USEDEFAULT,       /* where the window ends up on the screen */
               540,                 /* The programs width */
               250,                 /* and height in pixels */
               HWND_DESKTOP,        /* The window is a child-window to desktop */
               NULL,                /* No menu */
               hThisInstance,       /* Program Instance handler */
               NULL                 /* No Window Creation data */
           );

ボタンの1つを作成します。

CreateWindow(TEXT("button"), TEXT("Start"),
                 WS_VISIBLE | WS_CHILD,
                 x, y, width, height,
                 hwnd, (HMENU) 6, NULL, NULL);

また、ボタンをクリックするたびにイベントが発生することに気づきましたWM_KILLFOCUS。そのため、これが焦点の問題だと思います。また、WM_KILLFOCUSイベントをキャプチャしてから、フォーカスを再度設定しようとしましSetActiveWindowたが、プログラムがクラッシュしました。

どんな助けもいただければ幸いです:)

4

3 に答える 3

3

間違った関数(SetWindowActive)を使用していることがわかりました。Assaf Levyの答えは私には複雑に思えたので、これを回避する別の方法があるのではないかと思いました。SetFocusハンドルを提供することで、特定のウィンドウにフォーカスを与える関数を見つけることができました。

それを機能させるために必要なことは、必要なコードがWM_COMMANDブロック内で実行されたら、メインウィンドウのハンドルを使用してSetFocus関数を呼び出すことでした。これにより、メインウィンドウにフォーカスが戻り、イベントを受信できるようになりました。

SetFocusをWM_KILLFOCUSブロックに配置すると、ボタンやその他のコンポーネントがイベントに応答しなくなることに注意してください。

于 2011-12-15T12:18:57.713 に答える
2

これは仕様によるものです。メインウィンドウはですがwindow、ボタンはでありwindow、一度にフォーカスできるのは1つだけです。ボタンがフォーカスを「盗む」ことを望まない場合は、OnFocusハンドラー(またはインターセプトWM_SETFOCUS)を追加し、すぐにフォーカスを前のウィンドウに戻します(のにあると思いますWPARAMWM_SETFOCUS

簡単なハックは次のようになります。

  1. hMyButton = CreateWindow( "button"、...)。
  2. MyButtonProc(HWND、UINT、WPARAM、LPARAM)関数を定義します。
  3. SetWindowLong(hMyButton、GWL_WNDPROC、(LONG)MyButtonProc)を呼び出します。この関数によって返された値をg_OldButtonProcに保存します。
  4. MyButtonProc()内で、WM_SETFOCUSをキャッチし、SetFocus(hMyMainWindow)を呼び出します。メッセージがWM_SETFOCUSでない限り、MyButtonProc()関数の最後で常にCallWindowProc(h_OldButtonProc、hwnd、msg、...)を返します。

それはトリックを行います(テスト済み)。

于 2011-12-15T11:43:20.163 に答える
0

最初の答えは部分的に正確でした。ボタンをサブクラス化すると、「問題」を「取り除く」ことができます。ただし、親ウィンドウでWM_SETFOCUSを処理するか、サブクラスプロシージャまたはBN_SETFOCUSを処理すると、ボタンからフォーカスを取得するとUIが応答しなくなります。

サブクラスプロシージャでオーバーライドする必要があるのは、WM_LBUTTONUPです。マウスボタンを離すまでに、すでにWindowsボタンをクリックしています。

これは、ボタンがフォーカスを奪うためのまったくのゴミだと思います。これを防ぐBS_NO_STEAL_FOCUSのようなスタイルが必要です。別のウィンドウでキーの押下やスクロールを処理する場合は非常に面倒です。

/** Procedure for subclass. 
      This procedure is called first for the widget/control.
      Unhandled or partially handled message can goes to
      original procedure by calling DefSubclassProc(...).
      buttonProcEx takes all four params of normal procedure, plus a
       param for user defined object. 
      Note this is what win32 should have done in the first place.
 */
LRESULT CALLBACK buttonProcEx(HWND hwnd,uint msg,WPARAM,LPARAM,DWORD_PTR)
{
    if(msg == WM_LBUTTONUP) 
    {
     setFocus(GetParent(hwnd));
     return 0; //do not allow default behaviour
    }
    else return DefSubclassProc(hwnd,msg,wparam,lparam);
}


//Call this after creating your button

SetWindowSubclass((HWND)button、buttonProcEx、0、NULL);

or

struct Content {...}content; //lifetime should be long enough
SetWindowSubclass((HWND)button,buttonProcEx,0,(DWORD_PTR)&content);
于 2021-06-09T06:02:22.400 に答える