Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exiting a Form using ModalResult

Tags:

forms

delphi

I have a bunch of forms and I want to automate them so they would open and close by themselves.

I know how to get them to open (by having an OnActivate function), but I'm having trouble closing them.

So, for example, I have

procedure TProgressForm.FormActivate(Sender: TObject);
begin
  inherited;
  if FModItem.IsInQueue then
    begin
      RunBtnClick(Self);
      ModalResult := mrOK;
    end;    
end;

which runs a function. I want to close the window after the function has been run, which is what ModalResult should do.

(I've also tried adding the ModalResult line at the very end of the RunBtnClick procedure, but that didn't work either)

and I'm creating the form like this:

ProgForm := TProgressForm.Create(Self, FModItem);
Self.Visible := False;
try
 if ProgForm.ShowModal = mrOK then
  begin
    Left := ProgForm.Left;
    Top := ProgForm.Top;
  end;

I've been able to create buttons to close the form just by adding mrOK to the Modal Result in Object Inspector, but I can't seem to do it explicitly

Can anyone see why it's not working?

Thanks

like image 508
KingKong Avatar asked May 17 '11 19:05

KingKong


2 Answers

The reason for not working is that the VCL actively sets ModalResult to 0 in TCustomForm.ShowModal áfter showing the form, but prior to starting checking changes to ModalResult. So in OnActivate and in OnShow, you are to early.

The solution is to delay the notification. This can be done by a PostMessage, as follows:

const
  UM_ACTIVATED = WM_USER + 1;

type
  TProgressForm = class(TForm)
    procedure FormActivate(Sender: TObject);
  private
    procedure UMActivated(var Message: TMessage); message UM_ACTIVATED;
  end;

...

procedure TProgressForm.FormActivate(Sender: TObject);
begin
  PostMessage(Handle, UM_ACTIVATED, 0, 0);
end;

procedure TProgressForm.UMActivated(var Message: TMessage);
begin
  { Your code here }
  ModalResult := mrOk;
end;

Source: NLDelphi

like image 183
NGLN Avatar answered Oct 22 '22 20:10

NGLN


I'd override ShowModal and do the tests you now do in OnActvate from over there. This has two big advantages:

  • Doesn't show the form at all if it doesn't need to be shown. Initiating the form shutdown from OnActivate causes the form to "flicker" on screen: It's shown and immediately taken down.
  • Doesn't rely on code that's not under your control. You no longer care about the order of operation in the ancestor ShowModal, because you only call it if the form needs to actually be shown.

Of course, using a GUI element (a form) this way is a bit of code smell because it basically uses a GUI without the need for user interaction. This can undoubtedly be refactored to use an intermediary function that returns mrOk and does what RunBtnClick() does without needing the GUI, and creates the Form only if needed. I guess it's a cost-benefit kind of situation.

Code:

TMyForm = class(TForm)
....
public
  function ShowModal:Integer;override;
end;

function TMyForm.ShowModal:Integer;
begin
  if FModItem.IsInQueue then
    begin
      RunBtnClick(Self);
      Result := mrOK;
    end
  else
    Result := inherited ShowModal;
end;
like image 6
Cosmin Prund Avatar answered Oct 22 '22 18:10

Cosmin Prund