我在Experts-Exchange上找到了这个问题。
Control的OnExit在显示时会为新控件执行mouseup事件 另一个窗口
问题可以很容易地复制。
在表单上放置3个tedits。在edit1中写一个showmessage('exit') onexit事件运行程序给edit1焦点使用鼠标给出 edit3焦点,单击确定showmessage观察你怎么写不出来 现在编辑3中的任何内容,直到你用鼠标点击某处 形式!给edit2焦点,然后使用鼠标给予edit3焦点 观察如何在edit3中输入你想要的内容!
到目前为止,我已经确定问题在于edit3 当旧的控件onExit事件时,不会收到mouseup消息 显示任何类型的窗口,我也尝试过显示一个窗口 在onExit事件中我自己的形式,相同的结果。事实上,窗户是 在印象之后,鼠标在edit3之后被按下 你点击了Ok到showmessage
我想这是Delphi / Windows中的一个错误但是如何解决它?一世 知道我可以在edit3的onMouseDown事件上强制使用WM_LBUTTONUP(因为 它是该过程中调用的最后一个事件)但不仅如此 乏味,并不总是适用
我正在尝试做类似的事情:
在onexit事件中,我会显示一个警告框然后继续 正常 - 将焦点移动到用户实际点击的位置。 这可能吗?
答案 0 :(得分:6)
再次PostMessage
救援!将对话延迟一点,以便Windows可以完成焦点更改。发布消息而不是直接显示对话框:
const
WM_SHOWMYDIALOG = WM_APP + 321;
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
procedure Edit1Exit(Sender: TObject);
private
procedure WMSHOWMYDIALOG(var Message: TMessage); message WM_SHOWMYDIALOG;
end;
procedure TForm1.Edit1Exit(Sender: TObject);
begin
PostMessage(Self.Handle, WM_SHOWMYDIALOG, 0, 0);
end;
procedure TForm1.WMSHOWMYDIALOG(var Message: TMessage);
begin
ShowMessage('Nice one');
end;
一切都很好:)。
答案 1 :(得分:4)
我不太确定这种行为的原因是吃过的鼠标消息。无论如何,无论是否是这种情况,当您在控件的OnExit
事件中激活窗口时,您正在做的是在焦点改变时更改焦点。这是因为,窗口在WM_SETFOCUS
之前被激活,以便新聚焦的控件返回。不鼓励这样做,以下引用来自MSDN上的博客条目“Win32 Activation and Focus”的“最佳做法”部分:
避免在获得和/或失去焦点时手动更改焦点。这个 通常被证明容易出错。
由于激活窗口的模态特性,在焦点转移期间禁用控件的事实当然无济于事。如果你真的必须这样做,像Heinrich's answer这样的方法至少会延迟窗口的启动,直到焦点转移完成。
答案 2 :(得分:2)
在onexit事件中,我显示一个警告框,然后想要正常进行 - 将焦点移动到用户实际点击的位置。这可能吗?
是的,(Screen.)ActiveControl
将始终指向Edit3
:在调用ShowMessage之前和之后:
procedure TForm1.Edit1Exit(Sender: TObject);
begin
ShowMessage('Exit');
PostMessage(ActiveControl.Handle, WM_LBUTTONUP, 0, 0);
end;
但这只是为了你的问题的完整性!这当然不是小费也不是建议!请参阅Sertac的答案。