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

3

1

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?

Berenice answered 16/8, 2011 at 14:37 Comment(1)
Don't provide modal warnings in an OnExit event handler. Limit the warning to visual aids. If you need to show a modal warning, do it when submitting the form (clicking OK).Corsiglia
H
7

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 :)

Hibben answered 16/8, 2011 at 15:4 Comment(0)
B
4

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.

Beeswing answered 16/8, 2011 at 16:52 Comment(0)
C
2

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.

Corsiglia answered 16/8, 2011 at 17:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.