1

I need a help ...

I have two separated modal forms in Delphi VCL Forms application. Based on the solution from: How can I make a form that is not disabled when another form is shown modally?

I use EnableWindow(Self.Handle, True) and it works perfect: I can open and edit the first form and without closing it, open the second form. Both are active and editable.

The problem starts when I try to close first modal form without closing the second. It waits until the second one is closed.

Does exist any way to forced closing the first modal form (except the Self.Free because I need some information from model form in parent form) having the second one still open?

The code is quite simple:

Main form (with Button1):

procedure TfrMainForm.WMEnable(var _Msg: TWMEnable);
begin
  inherited;
     if not _Msg.Enabled and (Application.ModalLevel > 0) then Begin
          EnableWindow(Self.Handle, True);
     End;
end;


procedure TfrMainForm.Button1Click(Sender: TObject);
Var
     tmpSubForm: TfrSubForm;
begin
     tmpSubForm := TfrSubForm.Create(Self);
     Try
          tmpSubForm.ShowModal;
          //get some information from tmpSubForm
     Finally
          tmpSubForm.Free;
     End;
end;

"Child" form (do nothing - only open):

procedure TfrSubForm.WMEnable(var _Msg: TWMEnable);
begin
  inherited;
     if not _Msg.Enabled and (Application.ModalLevel > 0) then Begin
          EnableWindow(Self.Handle, True);
     End;
end;
Piotr
  • 33
  • 2
  • 2
  • 8
  • 1
    Reconsider your approach. If you don't want a form to be modal, don't show it modally. – Andreas Rejbrand Jun 25 '21 at 18:42
  • Things have gone too far. The solution I am looking for would solve the problem and if it does not exist then it will probably have to be done. – Piotr Jun 25 '21 at 18:46
  • But this doesn't make sense to begin with: just do it [MDI](https://en.wikipedia.org/wiki/Multiple-document_interface) wise and don't disable/modal any window just to fiddle with it afterwards. Just show the windows. Done. – AmigoJack Jun 25 '21 at 19:24
  • 4
    @Piotr *By definition*, a modal Form blocks the existing UI until the Form is closed. So, if you show 1 modal Form and then show a 2nd modal Form, the 1st Form is blocked until the 2nd Form is closed. *This is by design*. If you need both Forms to be interactive, including being able to close them independently, then modality is simply the wrong solution. – Remy Lebeau Jun 25 '21 at 19:38
  • Or, when you want the forms to be above the main form, change the z-order when the forms are shown using `Show`. – R. Hoek Jun 25 '21 at 20:13
  • @RemyLebeau "By definition, a modal Form blocks the existing UI until the Form is closed". Ok, it's clear but there is workarround to have both form active, so is there another workarround which allow close this modalform, which I need as first? – Piotr Jun 25 '21 at 20:15
  • 1
    That workaround is wrong. Modal windows are designed as @Remy has already described. If you don't want the standard modal behavior, then fix your code to not use modal windows in the first place. Trying to force inappropriate behavior into your app is simply setting you up for failure in the future. If you need more than one window active at a time, you should **not** be using modal windows at all. Period. – Ken White Jun 25 '21 at 20:41
  • Ok thank you all for your time and suggestions. I am heading more for a code change rather than a workaround – Piotr Jun 25 '21 at 21:31
  • Why are you using the solution from the linked Question on your Main Form from which you open your first modal form? Do you need your Main Form responsive even when modal form is open? If so then why even bother by using modal forms as using such solution on your Main Form defeats the purpose of what Modal Forms are for. – SilverWarior Jun 27 '21 at 03:17
  • Also is you second modal form always opened from your fist modal form? If so you could show your second modal form just as a regular form instead of modal form. Just don't forget to enable its window. This way you don't block your first modal form with the second modal form that you have now shown as regular form. So both are active even without the workaround from the linked question. Of course you now have to modify the first modal form so that it won't return the modal result if the second modal form is shown but instead store it in some private field and just hide. ... – SilverWarior Jun 27 '21 at 03:27
  • ... And then you modify your second modal form to check if first modal form has modal result stored in it private field when the second modal form is closing. If it has then that modal result should be assigned to first modal form modal result property which in turn will close the first modal form and resume normal application execution. – SilverWarior Jun 27 '21 at 03:30
  • Thank @SilverWarior. In the example I have given, I tried to show the essence of the problem in a possibly simplified form. My point was to avoid answering "why" questions but only get an answer to "how". Keeping in mind the information I gained here, I started to rebuild my project to showing modalless forms. – Piotr Jun 27 '21 at 07:26

1 Answers1

1

You can work in every window, regardless of whether it is a parent window or a child window.

DFM-Datei:

object frm: Tfrm
  Left = 0
  Top = 0
  Caption = 'frm'
  ClientHeight = 194
  ClientWidth = 283
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnClose = FormClose
  PixelsPerInch = 96
  TextHeight = 13
  object btnShow: TButton
    Left = 104
    Top = 132
    Width = 75
    Height = 25
    Caption = 'Show'
    TabOrder = 0
    OnClick = btnShowClick
  end
  object txt: TEdit
    Left = 8
    Top = 40
    Width = 121
    Height = 21
    TabOrder = 1
  end
end

Unit:

unit Unit1;

interface

uses
  System.SysUtils, System.Variants, System.Classes,
  Vcl.Controls, Vcl.Forms, Vcl.StdCtrls;

type
  Tfrm = class(TForm)
    btnShow: TButton;
    txt: TEdit;
    procedure btnShowClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
  protected
     procedure CreateParams(var Params: TCreateParams); override;
  public
    { Public-Deklarationen }
  end;

var
  frm: Tfrm;

implementation

{$R *.dfm}

procedure Tfrm.CreateParams(var Params: TCreateParams);
var
  Lfrm: TForm;
begin
  inherited CreateParams(Params);

  Lfrm := nil;
  if Owner is TControl then
    Lfrm := (GetParentForm(Owner as TControl, false) as TForm);
  if not Assigned(Lfrm) then
    Lfrm := Application.MainForm;

  if Assigned(Lfrm) and (Lfrm <> Self) then
  //Bind the child window to its parent window.
      Params.WndParent := Lfrm.Handle;
end;


procedure Tfrm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if Self <> Application.MainForm then
  //Action caHide -> caFree
    Action := caFree;
end;

procedure Tfrm.btnShowClick(Sender: TObject);
var
  Lfrm: Tfrm;
begin
  Lfrm := Tfrm.Create(Self);
  Lfrm.Top  := Top  + 10;
  Lfrm.Left := Left + 10;
  //Since you want to work in the parent window, the child window must not 
  //   display this in a showmodal manner!
  Lfrm.Show;
end;

end.
USauter
  • 295
  • 1
  • 9