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
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
I'd override ShowModal
and do the tests you now do in OnActvate
from over there. This has two big advantages:
OnActivate
causes the form to "flicker" on screen: It's shown and immediately taken down.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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With