I have two "modeless" forms:
- one is the special MainForm
- the other is a modeless form
You can see:
- both exist on the taskbar
- both have a taskbar button
- both can be independantly minimized
- both can be independantly restored
- neither is always on top (owned) by the other
Now show a modal form
From this modeless form, i want to show a modal one:
The Modal form is being constructed as:
var
frmExchangeConfirm: TfrmExchangeConfirm;
begin
frmExchangeConfirm := TfrmExchangeConfirm.Create(Application);
try
//Setting popupMode and popupParent still makes the MainForm disabled
// frmExchangeConfirm.PopupMode := pmExplicit;
// frmExchangeConfirm.PopupParent := Self; //owned by us
frmExchangeConfirm.OwnerForm := Self; //tell the form which owner to use
frmExchangeConfirm.ShowModal;
finally
frmExchangeConfirm.Free;
end;
The modal form is told which owner to use through a new OwnerForm
property:
protected
procedure SetOwnerForm(const Value: TForm);
public
property OwnerForm: TForm read GetOwnerForm write SetOwnerForm;
end;
which forces an handle recreation:
procedure TfrmExchangeConfirm.SetOwnerForm(const Value: TForm);
begin
FOwnerForm := Value;
if Self.HandleAllocated then
Self.RecreateWnd;
end;
and is then the second time through CreateParams
:
procedure TfrmExchangeConfirm.CreateParams(var Params: TCreateParams);
begin
inherited;
if FOwnerForm <> nil then
Params.WndParent := FOwnerForm.Handle;
end;
The problem is:
- once this owned modal form is shown, i cannot interact with the MainForm
- i cannot minimize the MainForm using the taskbar button
- i cannot minimize the Modal, or its owning parent, using the taskbar button
- if i minimize the modal form using the Minimize button, the MainForm disappears
- i can activate the MainForm using its taskbar button; but i cannot interact with it
I've asked this question about 7 times over the last decade. The last time i was promised that making the main form the MainForm would solve everything.
Bonus: WinForms has handled this correctly since .NET 1.0.
There is a lot of confusion about what a modal dialog is. A dialog is modal when you must interact with it before you can continue to use its owner. From the Windows Interface Design Guidelines:
Dialog boxes have two fundamental types:
- Modal dialog boxes require users to complete and close before continuing with the owner window. These dialog boxes are best used for critical or infrequent, one-off tasks that require completion before continuing.
- Modeless dialog boxes allow users to switch between the dialog box and the owner window as desired. These dialog boxes are best used for frequent, repetitive, on-going tasks.
Windows has the concept of an "owner". When a window is "owned" that will will always appear on top of its owner. When a window is "modal", it means that the owner is disabled until the modal task is complete.
You an see this effect in the ProgressDialog
API:
HRESULT StartProgressDialog( [in] HWND hwndParent, IUnknown *punkEnableModless, DWORD dwFlags, LPCVOID pvReserved );
hwndParent [in]
Type: HWND
A handle to the dialog box's parent window.dwFlags
Type: DWORD
PROGDLG_MODAL
The progress dialog box will be modal to the window specified by hwndParent. By default, a progress dialog box is modeless.
Sure, you could be mean, and disable all other windows
- in the thread
- the process
- or the system
But i want to have the correct behavior. I want to do:
- what Windows does
- what Office applications do
- what Beyond Compare does
- what WinForms does
- what WPF does
- what every application i've ever used does
- and what any user would expect
I've wanted this in my Delphi apps since 1998; when realized Delphi 3 didn't properly support Windows 95 and the taskbar.
ShowModal()
disables all visible windows that belong to the calling thread. This is by design. It is just not the design you want. You need to useShow()
instead ofShowModal()
in this case, disabling only theOwnerForm
when the confirm window is shown, and re-enabling theOwnerForm
when the confirm window is closed. – HolmiumShowModal
disables all windows in the application. But as a Windows developer, creating a Windows application, i am trying to show a window modally. On Windows A modal window is an owned window that requires the user to interact with it before they can return to operating the owner window.. The built-inShowModal
of the VCL doesn't so that; so i presume i have to write it myself? – CanailleMessageBox
once during a click, and the other 5 seconds later from a timer. You have two modal windows, both owned by the same owner, both interactiable. Only once the first modal dialog is dismissed does the owner become enabled. It seems Windows checks only enables the owner if it was the one to disable it. And it only disables it if it isn't already disabled. Which is a good note to add to my.ShowDialog
. Thanks! – Canaille