Delphi XE5: modal forms are not modal?
A couple of months ago Marco Cantu told us that modal forms are not directly supported on Android and we could use a new overloaded version of the same method:
function ShowModal: TModalResult; overload; procedure ShowModal(const ResultProc: TProc<TModalResult>); overload;
First method does raise an exception on Android and the second can be used as follows.
This classic code:
var dlg: TForm1; begin dlg := TForm1.Create(nil); try // select current value, if avaialble in the list dlg.ListBox1.ItemIndex := dlg.ListBox1.Items.IndexOf(edit1.Text); if dlg.ShowModal = mrOK then // if OK was pressed and an item is selected, pick it if dlg.ListBox1.ItemIndex >= 0 then edit1.Text := dlg.ListBox1.Items [dlg.ListBox1.ItemIndex]; finally dlg.Free; end; end;
should be rewritten using the new approach:
var dlg: TForm1; begin dlg := TForm1.Create(nil); // select current value, if avaialble in the list dlg.ListBox1.ItemIndex := dlg.ListBox1.Items.IndexOf(Edit1.Text); dlg.ShowModal( procedure(ModalResult: TModalResult) begin if ModalResult = mrOK then // if OK was pressed and an item is selected, pick it if dlg.ListBox1.ItemIndex >= 0 then edit1.Text := dlg.ListBox1.Items [dlg.ListBox1.ItemIndex]; dlg.DisposeOf; end); end;
The idea is clear and the motivation is clear. It uses an anonymous method with the code to be executed when the “supposedly modal” form is closed. This code works on all platforms. Thanks, Marco!
But let’s take a deeper look inside this new ShowModal:
procedure TCommonCustomForm.ShowModal(const ResultProc: TProc<TModalResult>); begin FResultProc := ResultProc; Show; end;
The form will be not modal on any platform! Thus, if we are going to write cross-platform code, we are suggested either to use conditional compilation or to stop using modal forms at all. Seriously?
Here is the pattern that I often use in my code:
with TForm1.Create(nil) do try ShowModal; finally Free; end;
Taking into account new ShowModal approach, this code can be rewritten as follows:
var Frm: TForm1; begin Frm := TForm1.Create(nil); ShowModal(procedure (Res: TModalResult) begin Frm.DisposeOf; end); end;
It works fine on all platforms, but the form is not modal anymore! So the best option for me would be:
var Frm: TForm1; begin Frm := TForm1.Create(nil); {$IFDEF ANDROID} Frm.ShowModal(procedure (Res: TModalResult) begin end); {$ELSE} try Frm.ShowModal; finally Frm.Free; end; {$ENDIF} end;
The form will be “pseudomodal” on Android and truly modal on other platforms. It’s better than nothing, but I hesitate to use IFDEFs too often – usually I have more than a couple of forms.
Finally, I have two rhetorical questions.
Why was new ShowModal approach not implemented like this:
procedure TCommonCustomForm.ShowModal(const ResultProc: TProc<TModalResult>); begin {$IFDEF ANDROID} FResultProc := ResultProc; Show; {$ELSE} ResultProc(ShowModal); {$ENDIF} end;
?
If this is not suitable for some reason, why did you call this method ShowModal, it has nothing to do with modal forms though?
Leave a Reply