当子按钮被按下时,窗口失去焦点

C++ Window losing focus when child button is pressed

本文关键字:窗口 失去 焦点 按钮      更新时间:2023-10-16

我正在尝试为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 */
           );

创建一个按钮:

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

我还注意到,每当我点击一个按钮,WM_KILLFOCUS事件被触发,这就是为什么我认为这是一个焦点问题。我还尝试捕获WM_KILLFOCUS事件,然后使用SetActiveWindow再次设置焦点,但这会使我的程序崩溃。

任何帮助都将是感激的:)

原来我使用了错误的函数(SetWindowActive)。阿萨夫·列维的回答对我来说似乎很复杂,我想可能有另一种解决方法。我设法找到SetFocus函数,通过提供它的句柄,将焦点放在任何给定的窗口。

要使其工作,我需要做的是,一旦必要的代码在WM_COMMAND块中执行,我调用SetFocus函数与主窗口的句柄。这使焦点回到主窗口,并允许它接收事件。

注意,将SetFocus放在WM_KILLFOCUS块中会导致按钮和其中的任何其他组件对事件没有响应。

这是设计。主窗口是window,但按钮是window,并且在任何给定时间只有一个可以有焦点。如果你不想让按钮"偷"焦点,添加一个OnFocus处理程序(或拦截WM_SETFOCUS),并立即将焦点返回到前一个窗口(我相信它在WM_SETFOCUSWPARAM中)。

一个简单的方法是:

  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)。总是在MyButtonProc()函数结束时返回CallWindowProc(h_OldButtonProc, hwnd, msg,…),除非消息是WM_SETFOCUS。

第一个答案部分准确。子类化按钮可以得到"rid"的"问题";然而,处理WM_SETFOCUS是在父窗口,或子类过程或BN_SETFOCUS将导致无响应的UI,如果你从按钮的焦点。

你应该在子类过程中重写的是WM_LBUTTONUP。因为当你松开鼠标按钮时,你已经点击了窗口按钮。

注:我认为这是一个完全垃圾的按钮来窃取焦点。应该有一个像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)按钮,buttonProcEx, 0, NULL);

or
struct Content {...}content; //lifetime should be long enough
SetWindowSubclass((HWND)button,buttonProcEx,0,(DWORD_PTR)&content);