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 */
           );

创建按钮之一:

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

这是设计使然。主窗口是 a window,但按钮是 a window,并且在任何给定时间只有一个可以拥有焦点。如果您不希望按钮“窃取”焦点,请添加一个 OnFocus 处理程序(或 intercept WM_SETFOCUS)并立即将焦点返回到前一个窗口(我相信它在WPARAMof 中WM_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)。始终在 MyButtonProc() 函数的末尾返回 CallWindowProc(h_OldButtonProc, hwnd, msg, ...),除非消息是 WM_SETFOCUS。

这样就可以解决问题(经过测试)。

于 2011-12-15T11:43:20.163 回答
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);
于 2021-06-09T06:02:22.400 回答