我正在尝试为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
设置焦点,但这会使我的程序崩溃。
任何帮助将不胜感激:)
答案 0 :(得分:2)
这是设计的。主窗口是window
,但按钮是window
,只有一个可以在任何给定时间聚焦。如果您不希望按钮“窃取”焦点,请添加OnFocus处理程序(或拦截WM_SETFOCUS
)并立即将焦点返回到上一个窗口(我相信它位于WPARAM
WM_SETFOCUS
1}})。
一个简单的黑客将是:
这将成功(测试)。
答案 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);