显示另一个窗口时,控件的 OnExit 会占用新控件的 mouseup 事件

发布于 2024-11-30 08:44:25 字数 855 浏览 0 评论 0 原文

我在 Experts-Exchange 上发现了这个问题。

显示时控件的 OnExit 会占用新控件的 mouseup 事件 另一个窗口

这个问题很容易复制。

在表单上放置 3 个编辑。在 edit1 中写入 showmessage('exit') onexit 事件 运行程序 给予 edit1 焦点 使用鼠标给予 edit3焦点,点击ok进入showmessage观察你怎么写不出来 现在编辑3中的任何内容,直到您用鼠标单击 形式 !给予 edit2 焦点,然后使用鼠标给予 edit3 焦点 现在就观察如何在 edit3 中输入您想要的内容!

到目前为止,我已经确定问题在于 edit3 旧控件 onExit 事件时未收到 mouseup 消息 显示任何类型的窗口,我也尝试过显示 我自己在 onExit 事件中的形式,结果相同。事实上,windows是 感觉鼠标在 edit3 上按住后 您已在显示消息中单击“确定”

我猜这是 Delphi/Windows 中的一个错误,但如何解决它?我 知道我可以在 edit3 的 onMouseDown 事件上强制 WM_LBUTTONUP (因为 它是该过程中调用的最后一个事件)但这不仅仅是 乏味,而且并不总是适用

我正在尝试做类似的事情:

在 onexit 事件中,我显示一个警告框,然后想要继续 像往常一样 - 将焦点移动到用户实际单击的位置。 这可能吗?

I found this question on Experts-Exchange.

Control's OnExit eats up mouseup event for new control when showing
another window

The problem can be replicated easily.

place 3 tedits on a form. write a showmessage('exit') in edit1's
onexit event run the program give edit1 focus use the mouse to give
edit3 focus, click ok to the showmessage observe how you can't write
anything in edit3 now, until you click with the mouse somewhere on the
form ! give edit2 focus, then use to the mouse to give edit3 focus
observe how you can type what you want in edit3 now !

So far I've established that the problem lies in the fact that edit3
doesn't receive a mouseup-message when the old controls onExit event
displays a window of any kind, i've tried it as well with showing a
form of my own in the onExit event, same result. In fact, windows is
under the impression that the mouse is held down over edit3 after
you've clicked Ok to the showmessage

I guess it's a bug in Delphi/Windows but how to work around it ? I
know i can force a WM_LBUTTONUP on edit3's onMouseDown event (since
its the last event called in the process) but that's more than
tedious, and not always applicable

I am trying to do something similiar:

In the onexit event I show a warningbox and then want to proceed
as normal - moving the focus to where the user in fact clicked.
Is that possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

无需解释 2024-12-07 08:44:25

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;

一切都很好:)

Once again PostMessage to the rescue! Defer your dialog just a little bit longer so that Windows can finish its focus change. Post yourself a message instead of showing the dialog directly:

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;

And everything is fine :)

野侃 2024-12-07 08:44:25

我不太确定这种行为的原因是被吃掉的老鼠消息。无论如何,无论情况是否如此,当您在控件的 OnExit 事件中激活窗口时,您所做的就是在焦点更改时更改焦点。这是因为,在新获得焦点的控件返回之前,该窗口是在 WM_SETFOCUS 之前激活的。这是不鼓励的,以下引用来自“Win32 激活和焦点',MSDN 上的博客条目:

避免在获得和/或失去焦点时手动更改焦点。这
通常被证明很容易出错。

由于激活窗口的模式性质,在焦点转移期间控件被禁用的事实当然不会有帮助。如果您确实必须这样做,请使用类似 Heinrich 的回答 至少会延迟窗口的启动,直到焦点转移完成。

I'm not so sure that the reason of the behavior is an eaten mouse message. Anyway, either that's the case or not, when you activate a window in an OnExit event of a control, what you're doing is, changing the focus while the focus is changing. That's because, the window is activated before WM_SETFOCUS for the newly focused control returns. This is discouraged, the below quote is from 'Best practices' section of 'Win32 Activation and Focus', a blog entry on MSDN:

Avoid manually changing focus when getting and/or losing focus. This
usually proves to be error prone.

The fact that the controls are disabled during focus transfer due to the modal nature of the activated window certainly would not help. If you really must do this, an approach like Heinrich's answer would at least delay the launch of the window till the focus transfer completes.

假装爱人 2024-12-07 08:44:25

在 onexit 事件中,我显示一个警告框,然后想正常进行 - 将焦点移动到用户实际单击的位置。这可能吗?

是的,(Screen.)ActiveControl 将始终指向 Edit3: 在调用 ShowMessage 之前和之后:

procedure TForm1.Edit1Exit(Sender: TObject);
begin
  ShowMessage('Exit');
  PostMessage(ActiveControl.Handle, WM_LBUTTONUP, 0, 0);
end;

但这只是为了问题的完整性!这当然不是提示或建议!请参阅 Sertac 的回答了解原因。

In the onexit event I show a warningbox and then want to proceed as normal - moving the focus to where the user in fact clicked. Is that possible?

Yes, (Screen.)ActiveControl will always point to Edit3: before and after the call to ShowMessage:

procedure TForm1.Edit1Exit(Sender: TObject);
begin
  ShowMessage('Exit');
  PostMessage(ActiveControl.Handle, WM_LBUTTONUP, 0, 0);
end;

But this is just for completeness sake to your question! And it certainly is no tip nor advice! See Sertac's answer for the reason.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文