11
votes

I've got an application where there's a main background form, from there user can only non-modal forms that maintains different part of the system. The non-modal forms overrides the CreateParams method so each one displays a button in the start task bar:

procedure TfmMaterialsPlanning.CreateParams(var Params: TCreateParams);
begin
   inherited;
   //create a new window on the task bar when this form is created
   Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
end;

In effect, a user can open a non-modal form that maintains 'Apples', another non-modal form that maintains 'Oranges', and use the start menu bar to easily switch between the two.

However, if they open a modal form from the 'Apples' form, e.g. to set options, preferences, etc, then they can't use the 'Oranges' forms until they close the modal form.

Is it possible to make a modal form modal to the parent form only? So if they open the Apple's options form, they can't use the Apples maintenance form, but can still use the Oranges maintenance form?

5

5 Answers

6
votes

If you have a look at the source code of TCustomForm.ShowModal() you will see that the VCL does not use the Windows API call for showing modal dialogs, but that it does instead disable all other forms in the application while the modal form is shown. You can of course try the very same, just Show() the form-modal dialog, then disable the parent, then re-enable it after the form-modal dialog has been closed. There needs to be a central place where you keep track of form-modal dialogs, the forms that need to be re-enabled and so on. You should however test thoroughly whether the code does indeed what you want it to do, even when switching back and forth between applications, when minimizing the application and so on.

Having said that - I don't think that this a good idea at all. It breaks all assumptions a Windows user makes about the behaviour of applications. Unlike in Mac OS X there is no distinction in Windows between application-modal and form-modal dialogs, and you should stick to the behaviour consistent with the platform your are programming against.

There is most probably a better way to structure your UI. Have a look at the relevant page for dialog boxes in the "Windows User Experience Interaction Guidelines". Modal dialogs are better avoided as much as possible, the linked guidelines show better alternatives for many use cases. If you limit the use of modal dialogs, maybe you do no longer need the form-modal dialogs.

3
votes

This post has a nice trick to acomplish your needs: http://blogs.teamb.com/deepakshenoy/2006/08/21/26864

The summary is to reenable the nonmodal window you want when a modal window disabled it.

0
votes

Couldn't you achieve the same effect by preventing the "Apples" form from accepting focus while its child form is open?

0
votes

Just as an aside (although it would be an awful lot of work), another approach to this problem is the way Google's chrome went, where each "tab" is a separate process but appear to the user as a single integrated application.

Even though this approach would achieve what you wanted, I would have to agree with the comment above that this would break a user assumptions and expectations about modal behaviour.

-1
votes

This is possible, if you create each non-modal form in its own thread. Each modal form will then block the thread it belongs to.

Edit: This should be possible, even though the vcl is not thread-safe. Please take a look at Alexeys explanation of how this can be done:

So if you have a set of forms that should live in a separate thread then place them into one dll, compile it without packages and use! It will work and it will be thread-safe.