Jump to content
Mike Torrettinni

Why is ShowMesssage blocking all visible forms?

Recommended Posts

I have an example where I create multiple instances of FormX from Main Form. When FormX are created, I can focus individual form or Main Form without problems, but as soon as one of the forms uses ShowMessage or (another Form.ShowModal) all forms are blocked, and waiting for focus to go back to the form.

 

Screenshot of MainForm and 3x FormX, and I can focus any of them - forms are shown by Show method

 

image.thumb.png.c66c37292b6924e02f65770243c83294.png

 

As soon as one of the forms uses ShowMessage('msg...'), the focus is on the message window and none of the other forms can be focused until this message window is closed:

 

image.thumb.png.a338d57860649b0d36b2d11b881dd755.png

 

 

This is very simple example, I create forms like this:


procedure TForm8.Button1Click(Sender: TObject);
var vNewForm: TFormX;
begin
  vNewForm := TFormX.Create(Application);
  fForms.Add(vNewForm);
  fForms.Last.Show;
end;

 

Is there anyway how to be able to work with other forms, even though one of them is waiting for another window (dialog box, or another Form) to close?

Share this post


Link to post

So, what I'm trying to do: I have monitoring application and can monitor different different data, files, folders, disks... main form lists all available services to monitor and user selects which ones he wants to monitor and opens up new form with all the details.

So, user can have multiple forms open and can work with the monitored data.

It can happen that one of the monitored services need attention or connection get lost. In this case a ShowMessage (or new Form.ShowModal) is supposed to alert user with message, while other forms should continue monitoring. User can then decide to reconnect or close the form that is showing an alert, while other should just continue monitoring.

 

So, a modal window that blocks only the form it was called from, would be really useful in this case. Any ideas?

 

 

Edited by Mike Torrettinni

Share this post


Link to post
49 minutes ago, Mike Torrettinni said:

It can happen that one of the monitored services need attention or connection get lost. In this case a ShowMessage (or new Form.ShowModal) is supposed to alert user with message, while other forms should continue monitoring. User can then decide to reconnect or close the form that is showing an alert, while other should just continue monitoring.

Then don't use ShowMessage() for that.  It displays a modal TForm whose owner window (in Win32 API terms, not VCL terms) is the currently active TForm.  An owned window is always on top of its owning window.

 

For what you describe, use a normal TForm instead of ShowMessage().  Set its PopupParent property to the monitoring TForm that needs attention, and then show the popup TForm.  This way, the popup Tform stays on top of only its monitoring TForm, but other TForms can appear on top of the popup TForm.

 

Otherwise, change your UI to not use a popup TForm at all.  Put a visible message inside the TForm that needs attention.

  • Like 3
  • Thanks 1

Share this post


Link to post

Great, thanks! Also annoying thing about multiple forms opened is that ShowMessage can show up behind the form, and since it's modal, sometimes you can't access it to close it - annoying.

4 hours ago, Remy Lebeau said:

Otherwise, change your UI to not use a popup TForm at all.  Put a visible message inside the TForm that needs attention.

Saw and interesting example where the Form was dimmed, but the notification message was not - very noticeable and no modal windows.

Share this post


Link to post
3 hours ago, Mike Torrettinni said:

Saw and interesting example where the Form was dimmed, but the notification message was not - very noticeable and no modal windows.

Sounds like an example of doing something just because you can.

Share this post


Link to post
45 minutes ago, Anders Melander said:

Sounds like an example of doing something just because you can.

Something new and I will probably go through a few variations until I end up with something I'm OK with. You should see how I choose icons for my projects, I can get crazy picky for that perfect icon and color... 🙂

Share this post


Link to post
On 3/21/2020 at 1:11 AM, Mike Torrettinni said:

Saw and interesting example where the Form was dimmed, but the notification message was not - very noticeable and no modal windows.

This has come from web, I guess. It's a very frequent pattern there

Share this post


Link to post

why dont you just create a custom form and use that in place of the dlg then you have much more control over it.

Share this post


Link to post
2 minutes ago, WpgnGaming said:

why dont you just create a custom form and use that in place of the dlg then you have much more control over it.

Well, idea was to have modal window over the non-modal form that needs attention from user (either to refresh the info, close or do something else that needs user attention/intervention). So, what would modal custom form be different than modal message window? It would still block all other forms, right?

Share this post


Link to post

just make it, so it dont stay on top by having it set to normal in plaace of ontop

 

FormStyle := fsNormal;

Share this post


Link to post

I need to make it on top of the form that calls it - so it 'blocks' the original form from user access, until message form is closed. Would you suggestion work like this?

Share this post


Link to post
6 hours ago, Mike Torrettinni said:

I need to make it on top of the form that calls it - so it 'blocks' the original form from user access, until message form is closed.

That is exactly what a TForm's PopupParent property is meant for.  A TForm stays on top of its PopupParent Form, it can never go behind the PopupParent.  Like I described earlier in this same discussion.

 

Otherwise, just use a TFrame instead.  Put it on top of the TForm that needs to be "blocked", and disable access to the TForm's controls until the TFrame is dismissed.

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post

Talking from an end-user perspective I'd go insane if one application would open tens of forms. I have one screen only and it will be polluted within seconds.

What I would do is to have only one form, with a list on the left and a PageControl on the right. Instead of forms, create a new TabSheet for the monitors. When there is an alert, you can change the ImageIndex property to change the icon of the tab sheet; signaling the user that attention is needed.

 

As for the "messages" I would put an invisible panel inside every tab sheet, on top of everything. It would contain only a TMemo and a button to dismiss. This way if multiple alerts are generated without interaction, you can append it to the memo instead of having 3-4 popup windows for a single monitor.

Edited by aehimself
  • Like 1

Share this post


Link to post
3 minutes ago, aehimself said:

Talking from an end-user perspective I'd go insane if one application would open tens of forms. I have one screen only and it will be polluted within seconds.

Yes, of course, make sense. Unless you use 'open in new window' option for each resource you want monitored live data.

 

4 minutes ago, aehimself said:

As for the "messages" I would put an invisible panel inside every tab sheet, on top of everything. It would contain only a TMemo and a button to dismiss

I tested similar option, too. With good results.

 

15 hours ago, Remy Lebeau said:

That is exactly what a TForm's PopupParent property is meant for.  A TForm stays on top of its PopupParent Form, it can never go behind the PopupParent.  Like I described earlier in this same discussion.

  

Otherwise, just use a TFrame instead.  Put it on top of the TForm that needs to be "blocked", and disable access to the TForm's controls until the TFrame is dismissed. 

Thanks, I have to put this on hold for a little while, so when I get back to it, I will see what implementation will be suitable.

Share this post


Link to post
33 minutes ago, Mike Torrettinni said:

Yes, of course, make sense. Unless you use 'open in new window' option for each resource you want monitored live data.

Yes, makes sense; did not think of this. What you can do is to have a TFrame with basic functionality (placeholder for the monitor, invisible panel, etc) and add a "pop out" button there.

When you click it, you simply create a TForm and move the current TFrame on that new form. Just, don't forget to free the tabsheet 🙂

 

I was also experimenting with auto-docking tabsheets a while ago. When you drag them out they turned to forms automatically, and vice versa. Unfortunately though the performance was so bad (flickering and lagging) that I abandoned the idea. Most probably I was doing something wrong; you can look in this direction too instead of a pop-out button.

 

Edit: Seems pretty easy, I don't know what I messed up before.

 

 

Edit-edit: It works, but the flickering is still there when dragging around the "child" window; even if DoubleBuffered is on.

If you don't want to watch the video: Set DockSite of the PageControl to True. Set DragKind of the "child" form to dkDock and in the OnClose event set the Action to caFree. Then, create your "child" forms like this:

Var
 f: TForm2;
begin
 f := TForm2.Create(Application);
 f.ManualDock(PageControl1);
 f.Show;
End;

 

Edited by aehimself

Share this post


Link to post
On 3/20/2020 at 11:11 PM, Mike Torrettinni said:

Also annoying thing about multiple forms opened is that ShowMessage can show up behind the form, and since it's modal, sometimes you can't access it to close it - annoying. 

I have the same problem too.

As it turned out, it is caused by a 3th party component, that is "overriding" all forms.

For me it was the "skinning all form" component called: sSkinManager created by: AlphaSkins

 

Had to turn OFF automatic skinning rules by setting at Design time:

SkinManager1.SkinningRules := [];

image.png.7b0a70713eec28f475d615d29d965859.png

 

But I'm not sure if that's fixing it properly.

 

I've also just created my own custom ShowMessage dialog form,

 ... but yet looking for a way to override all "ShowMessage(...)" function everywhere in my program.

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×