这是一个已知问题。当您在完成最后一次焦点更改之前更改焦点时,Windows 会出现问题(例如,焦点开始从 更改Edit1
为Edit2
,但Edit1.OnExit
会执行一些操作以将焦点更改为另一个控件或表单。
例如,当应用程序尝试在OnExit
事件中进行验证,然后在验证失败时尝试将焦点返回到原始控件时,就会发生这种情况。
最简单的解决方案是向您的表单句柄发布消息OnExit
,并在那里处理焦点更改需求。一旦目标控件获得输入焦点,它将触发,Windows 不会感到困惑。
const
UM_EDIT1_EXITED = WM_USER + 1;
type
TForm1=class(TForm)
...
private
procedure UMEdit1Exited(var Msg: TMessage); message UM_EDIT1_EXITED;
end;
implementation
procedure TForm1.Edit1Exit(Sender: TObject);
begin
PostMessage(Handle, UM_EDIT1_EXITED, 0, 0);
end;
procedure TForm1.UMEdit1Exited(var Msg: TMessage);
begin
// Show your other form here
end;
来自TeamB的 Peter 博士的旧 Borland NG 帖子:
这是我关于“从 OnExit 显示对话框”问题的一般布道:
如果触发了 OnExit 处理程序(这发生在响应 Windows 消息 WM_KILLFOCUS),则 Windows 处于焦点更改之中。如果您在处理程序中执行导致另一个焦点更改的操作(例如弹出消息框或执行 SetFocus 调用),Windows 会非常混乱。缺少的光标就是一个症状。
如果您必须从 OnExit 处理程序向您的用户显示消息,请这样做:
在单元的接口部分的某处为用户消息定义一个常量,在表单的类型声明上方
'常量 UM_VALIDATE = WM_USER + 200;'
为您的表单提供此消息的处理程序,最好放在类声明的私有部分:
Procedure UMValidate( Var Msg: TMessage ); message UM_VALIDATE;
如果字段的内容不正确,则从 OnExit 处理程序向表单发布 UM_VALIDATE 消息。您可以在消息的 wparam 和 lparam 参数中传递附加信息,例如错误号和 Sender 对象。事实上,您可以在 UMValidate 处理程序中进行整个验证!