C ++窗口在按下子按钮时失去焦点

时间:2011-12-15 11:12:07

标签: c++ winapi win32gui

我正在尝试为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设置焦点,但这会使我的程序崩溃。

任何帮助将不胜感激:)

3 个答案:

答案 0 :(得分:2)

这是设计的。主窗口是window,但按钮是window,只有一个可以在任何给定时间聚焦。如果您不希望按钮“窃取”焦点,请添加OnFocus处理程序(或拦截WM_SETFOCUS)并立即将焦点返回到上一个窗口(我相信它位于WPARAM WM_SETFOCUS 1}})。

一个简单的黑客将是:

  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。
  5. 这将成功(测试)。

答案 1 :(得分:2)

事实证明我使用了错误的功能(SetWindowActive)。 Assaf Levy的回答对我来说似乎很复杂,我认为可能还有另一种方法。我设法找到SetFocus函数,通过提供它的句柄,将焦点放在任何给定的窗口上。

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

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

答案 2 :(得分:0)

第一个答案部分准确。将按钮子类化可以“摆脱”“问题”;但是在父窗口、子类过程或 BN_SETFOCUS 中处理 WM_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);