8

I have a Modal form, and in the Ok button it processes some information, that I need in the form that called the modal form.

How can I get it out before it closes?

Or delay the close till I say it can close.

DRokie
  • 705
  • 2
  • 9
  • 20

6 Answers6

11

I expect that your OK button has ModalResult set to mrOK. If you want to add error checking to the OK button then change that to mrNone. Add an OnClick handler to the button which does whatever checking or processing you need. If it determines that the form can close, set Self.ModalResult := mrOK in the OnClick handler.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 3
    Congrats on having reached the top of [all time Delphi users](http://stackoverflow.com/tags/delphi/topusers). – NGLN Oct 19 '11 at 14:19
  • Anyone know why This answer has 2 downvotes? It appears to be the only answer that address the "delay the close till I say it can close" part of the question. – David Heffernan Oct 19 '11 at 14:37
  • I needed to do something before the form was closed, this solved my issue! – Soon Santos Dec 21 '18 at 10:47
7

Do you really need to access the information before the form is closed? Delaying the closing of a form will affect the users experience of the app (unless it's fast enough that they don't notice - in which case why delay it at all?)

A closed form is still available in memory for the caller (unless the close action is caFreeOnClose). So you should be able to add public properties to the form which you can then access within the caller.

e.g

Type Form2 = Class(TForm)
public
    //Add a public property here
end;

From the caller:

if Form2.ShowModal = mrOk then
begin
    InformationIWant = Form2.PublicProperty;
end;
James
  • 9,774
  • 5
  • 34
  • 58
  • A few problems here: 1. `Show` is not a function. You presumably mean `ShowModal`. 2. You don't address the part of the question that talks about "delay the close till I say it can close". – David Heffernan Oct 19 '11 at 14:37
  • @DavidHeffernan: Thanks David, I don't currently have access to Delphi so couldn't check. I've updated the answer. I've tried to address your second point – James Oct 19 '11 at 15:34
  • It's common to want to validate data and block the form closing. That has to happen inside the form and not after `ShowModal` returns. – David Heffernan Oct 19 '11 at 16:36
  • @DavidHeffernan: I have the idea that this question is not about validating data, but about accessing the data of the dialog in the calling code. Which JamesB addresses in his answer. – The_Fox Oct 20 '11 at 07:07
  • "unless the close action is caFreeOnClose" - Unfortunately, this will happen in many (most?) cases. – Gabriel Sep 20 '16 at 16:10
5

Just a combination of what others are saying.

It is a good idea to formalize how to validate and get data out from a modal dialog. Using the same technique over and over again makes everything easier to maintain and read.

An example :

Type TFormModal = Class(TForm)
  procedure OnOkClick( Sender : TObject);
  function ValidateInterface : boolean;

public
  procedure SetInterface( input data here);
  procedure GetInterface( output data here);

end;

procedure TFormModal.OnOkClick( Sender : TObject);
begin
  if ValidateInterface 
    then modalResult := mrOk
    else modalResult := mrNone;
end;

from your main form :

procedure MainForm.OnShowMyModalFormClick( sender : TObject);
var
  myModal : TFormModal;
begin
  ...
  myModal := TFormModal.Create( nil);
  try
    myModal.SetInterface( ...);
    if (myModal.ShowModal = mrOk) then myModal.GetInterface(...);

  finally
    myModal.Free;
  end;
  ...
end;
LU RD
  • 34,438
  • 5
  • 88
  • 296
2

As addition to JamesB's answer.

You must call Form2.Free, áfter you take the information you want.

I generally add a new function to the second form's unit, something like:

type
  TForm2 = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
    InformationIWant : SomeType;
  end;

var
  Form2: TForm2;

function ReturnValue : SomeType

implementation

function ReturnValue : Sometype;
begin
   try 
     if Form2 = nil then
        Form2 := TForm2.Create(nil);
     Form2.Windowstate := wsNormal;
     Form2.BringToFront;
     SetForegroundWindow(Application.Handle);     
     if Form2.ShowModal then
        Result := InformationIWant
   finally
      FreeAndNil(Form2);
   end;
end;
Community
  • 1
  • 1
Kipow
  • 51
  • 2
  • The FreeAndNil(Form2) makes it clear that Form2 can be a local variable in `ReturnValue`, instead of a global one. – mjn Oct 19 '11 at 15:32
  • IMPORTANT: It is preferable to call .Release on a form instead of .Free. Release will give the form a chance to process all the remaining messages in the queue. https://stackoverflow.com/questions/708847/delphi-is-it-ok-for-a-form-to-free-it-self – Gabriel Nov 30 '18 at 08:34
2

An alternative to David’s answer is to use either OnClose or OnCloseQuery events. With OnCloseQuery you can prevent the form from closing by setting CanClose := false;

crefird
  • 1,590
  • 11
  • 17
0

Let's say you want to do more than to simply know if the user pressed the OK or Cancel button in your modal from.
Let's suppose you need to set some parameters for the MainFrom in FromSettings.

  1. Create and show the FormSettings modal
  2. When the user presses the "OK" (or "Apply") button in FormSettings to close the form, you transfer all your data from FormSettings to MainForm
  3. Finally call FormSettings.Close or better FormSettings.Release (not FormSettings.Free) to close the form.

Of course the MainFrom has to have some exposed (public) fields in which you receive the data from FormSettings, like:

 FormMain.AlphaBlendValue := FormSettings.spnTransparency;

Hint 1:
You don't necessary have to transfer data from FormSettings into MainForm. If it better suits you, you can also save the data in a global variable, or record.

Hint 2:
I personally don't use the method described above, which is designed to save RAM when the FormSettings is freed.
I actually never destroy the SettingsForm. Some people would say that this is "horror" but computers today have 4GB or RAM (at least) and a form with some controls on it will "waste" a very very little amount of that RAM. So, the FormSettings in is memory all the time. When I need some values, I just let the MainForm to read them from FormSettings.
Again... this is definitively the recommended way to do it. It is the convenient way :) You have been warned!

Gabriel
  • 20,797
  • 27
  • 159
  • 293