October 2, 2013
FireMonkey in Delphi XE5 introduces a new mechanism for working with modal dialog boxes, due to the fact that the old model is not directly supported on Android.
FireMonkey in Delphi XE5 introduces a new mechanism for working with modal dialog boxes, due to the fact that the old model is not directly supported on Android. So let's start from this last point, or actually from Windows, where the "modal" form idea originated. The following description is not terribly detailed, but meant to give you an idea of what's at stake.
On Windows, applications have a message processing loop and for each incoming user or application message a user executes some code. VCL and FireMonkey applications have it. The special ShowModal method allows you to stop execution of a message and have a secondary message handling loop. This is how a modal form works, blocking input (like mouse clicks) to the other forms of the same application.
The advantage for a developer is that coding around a ShowModal call is generally much easier than simply showing a secondary form, as the main form can "wait for the modal form to close". While with a modeless approach you need to find a way to communicate back the result of a user operation to the main form, with modal forms this becomes trivial.
As an example, let's consider this classic code, which uses a secondary for with a listbox to let the user select a value:
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;
This code works basically unchanged on VCL and FireMonkey.
Apple operating systems (both OS X and iOS) follow the same approach, allowing FireMonkey dialogs to work basically in the same way. So the code above keeps working unchanged on Mac and on the iOS platform, thanks to FireMonkey. Of course, on iOS the situation is not the same, because a secondary form (modal or not) will always cover the entire screen, making it impossible for the user to interact with other forms (again, regardless the secondary form is modal or not).
Android, however, lacks the same concept. Showing a form is not an issue, but if you want to simulate a modal form (blocking the calling code and still receiving events) you need to spawn a separate activity (almost another application). In other words, making modal forms work on Android is quite complex. A non-modal form covers the entire screen, so no big deal, right? This is actually wrong. Although for the user experience, modal or modeless will work the same, for the developer changing the code to account for modeless forms would be a lot of work.
So what happens in Delphi XE5 for Android? The classic ShowModal doesn't work any more (it does raise an exception on Android), but a new overloaded version of the same method is available:
function ShowModal: TModalResult; overload;
procedure ShowModal(const ResultProc: TProc<TModalResult>); overload;
The new version, as you can see, is quite special as it uses an anonymous method with the code to be executed when the "supposedly modal" form is closed. The anonymous method received the modal result as parameter. This is basically the code you'd write in the code block within the "if ShowModal" statement.
Here is the same code I had above rewritten using the the new approach (which is compulsory an Android but you can adopt on all platforms):
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);
Notice that the core code is almost identical, as the anonymous method can refer to controls on the calling form, although it will be executed by the secondary one. There is a difference which is the way the form is freed (forcing destruction on ARC, which should not be required).
So here it is: Anonymous ShowModal, required by Android and available on all FireMonkey platforms in XE5.
posted by
marcocantu @ 9:19PM | 25 Comments
[0 Pending]
25 Comments
Delphi XE5 Anonymous ShowModal and Android
Your example code would cause a memory leak under
Windows and OSX, so the only way to write this platform-
independently is to explicitly free everything that you
create.
It's not on top of my wish list, but are there any plans
to ever implement ARC in the win32/win64 compiler, or to
create a windows target with the LLVM based compiler?
Comment by Wouter on October 3, 00:07
Delphi XE5 Anonymous ShowModal and Android
Wouter, the code works with no memory leak. On Windows and Mac
(non-ARC), the DisposeOf method calls Free, which in turn calls Destroy.
On iOS and Android (ARC) DisposeOf forces the destruction even if there
are still pending references.
Plans for ARC in the Win32 compiler are being discussed internally. There
are many reasons in favor, but also lots of reasons against this change.
LLVM on Windows won't be easy until LLVM compiler speed increases
significantly.
Comment by Marco Cantu
[http://www.marcocantu.com]
on October 3, 08:17
Future of Windows compilers
What will happen with 8-bit strings in future Windows
compilers? Not having them on mobile has proven to be
a showstopper for me, and on Windows that would be
game over.
Comment by Dalija Prasnikar
[]
on October 3, 10:38
Delphi XE5 Anonymous ShowModal and Android
This is a big headache.
I use ShowModal all the time, where a window calls the
other, waiting for the closing and reacts according to
the response ModalResult. The lack of authentic
ShowModal and the workaround suggested buries a
practice simple, stylish and safe that I use happy for
15 years.
Comment by Nelson H C Nepomuceno
[http://www.integrasoftware.com.br]
on October 3, 13:37
Delphi XE5 Anonymous ShowModal and Android
Nelson,
we are aware this is an unwanted change. On all platforms but Android
(and with VCL, of course) you can keep using the classic ShowModal. On
Android or for x-platform code, you have to move to the new, but almost
identical coding style. Or just get rid of modal forms and use other ways
to pass back the results, which would require a significant rewrite.
-Marco
Comment by Marco Cantu
[http://www.marcocantu.com]
on October 3, 14:16
Delphi XE5 Anonymous ShowModal and Android
Marco,
I fear the day that Emb brings ARC to Desktop... That is
the day that Delphi will die for me. Our code is so
complex that we would have to review millions (5
millions exactly) of lines of codes to support ARC
Comment by Eric
[http://www.digifort.com.br]
on October 3, 15:52
Delphi XE5 Anonymous ShowModal and Android
Eric, this is exactly the reason we cannot and will not port ARC to
desktop as the only solution. VCL lives and will continue living in the
non-ARC world. The only option would be to have ARC alongside, but
this will cause a significant amount of trouble, hardly worth. As I
mentioned, there are many reasons against ARC on Win32.
Even more an LLVm compiler will imply that for your 5 million lines you'll
have to take a few coffees every time you press Ctrl-F9. We don't want
C++ Compiler speed in Delphi ;-)
Comment by Marco Cantu
[http://www.marcocantu.com]
on October 3, 16:00
Delphi XE5 Anonymous ShowModal and Android
Marco,
That is great to know! I can now rest assured that I
can continue relying on Delphi for my main
application. Really when I heard that Emb was
evaluating the possibility of bringing ARC to Desktop
I got in panic.
ARC is really nice to work with in the Mobile, I´m
already working with it, but it is not as
straightforward as one may think and it has it´s
gotcha here and there.
If you develop a project from scratch with ARC in mind
you will never get into trouble... but when you
already have such complex structure as we do, it is
simply impossible to port it to ARC.
Ohhh another thing is the speed, as you mentioned.
Today we brag about the speed of the compiler, and I
also don´t want to see C++ compiler speed in Delphi.
Comment by Eric
[http://www.digifort.com.br]
on October 3, 19:35
Delphi XE5 Anonymous ShowModal and Android
Marco,
Just curious. Do you know why LLVM so slower? is it
optimization passes? what if try to build in debug mode
without optimizations at all? (i.e. how comparable
speed would be?)
Comment by Den on October 4, 16:31
Delphi XE5 Anonymous ShowModal and Android
Although this is getting "ShowModal and Android" off
topic, please keep us updated on "Win32 and ARC". I
believe it's a very interesting and important topic.
Comment by Günther the Beautiful
[]
on October 4, 19:50
Delphi XE5 Anonymous ShowModal and Android
One more vote for the separate posting on the "Win32
and LLVM" topic.
Comment by Torbins
[]
on October 5, 14:01
Delphi XE5 Anonymous ShowModal and Android
I am using this method on Android.
My dialog has a TEdit
It works fine the first time. Then when the "dialog"
opens the next time, I press the TEdit on the device
and it crashes the app.
Comment by brent
[http://justapps.com]
on October 9, 19:15
Delphi XE5 Anonymous ShowModal and Android
To me this method does not work.
Same issue as flagged by brent.
First time it works ok. Then next time you open a
dialog a segmentation fault is fired.
The problem appears also in case no controls at all
are present on the "dialog" (a part of course a button
to assign the modalresult).
Any suggestion?
Tnx
Comment by Max LE Bon on November 28, 15:32
Delphi XE5 Anonymous ShowModal and Android
Has anything changed with XE5 Upd1 as it doesn't quite
work for me.
1) How are you closing the object of class TForm1?
- I'm using the ModalResult property of a TSpeedButton
2) The TForm1 instance remains displayed after being
disposed of, if I tap the screen the calling form is
displayed again.
This is on my Xperia Play - Android 2.3.4
Comment by Steve Childs
[]
on December 6, 12:09
Delphi XE5 Anonymous ShowModal and Android
(and on my HTC One it causes a Seg Fault).
Sorry Marco, looks like its back to the drawing board
for Modal dialogs on Android.
Comment by Steve Childs
[]
on December 6, 12:13
Delphi XE5 Anonymous ShowModal and Android
I'm getting the same issue on Google Nexus 7. Take the
example code as is and form doesn't clear from screen,
Segment fault.
Looking at alternative UI design, but it would be mice
to be able to do this. Keeping certain functionality
on a separate form for use in different places makes a
lot of sense.
Comment by Dave Martel on December 13, 09:57
Delphi XE5 Anonymous ShowModal and Android
Using Delphi XE5 Update 2, running on Windows, the
code produce an access violation at program exit in
the _halt0() procedure.
Comment by Francois Piette
[http://francois-piette.blogspot.be]
on December 18, 17:09
Delphi XE5 Anonymous ShowModal and Android
Francois, yes, there are some open issues on the Windows side of the
new overloaded ShowModal.
Comment by Marco Cantu
[http://www.marcocantu.com]
on December 23, 11:38
Delphi XE5 Anonymous ShowModal and Android
What do you do on the modal form side? Do you assign
the modalresult to the "Ok" and "Cancel" buttons, or
do you create an onclick event for each button. If so,
what code is used. I CANT GET THE Modal form to close
and return the result
Comment by Shane on March 6, 15:29
Delphi XE5 Anonymous ShowModal and Android
Hello Marco
with the following code (similar to your) i have an
access violation in disposeof (Delphi XE6)
begin
form2:=Tform2.Create(nil);
form2.ShowModal(
procedure(modalresult:Tmodalresult)
begin
if modalresult=mrOk then
showmessage(You have pressed OK')
else showmessage('You have pressed Cancel');
form2.DisposeOf;
end
);
end;
I don't have errors if:
1) Remove disposeof
2) in form2 i define the following onclose event:
action:=Tcloseaction.caFree;
Comment by Roberto on July 28, 16:21
Delphi XE5 Anonymous ShowModal and Android
Hello Marco
I have tries every method to get an answer from the
user (i.e. ModalResult in this case) except (so far)
for using Roberto on July 28, 16:21 modifications.
Your method unmodified works the first time called,
but on subsequent calls the application quits or
crashes.
Comment by jzingaleii on October 8, 23:53
Delphi XE5 Anonymous ShowModal and Android
Calling DisposeOf inside the anonymous method is
wrong. The anonymous frame relies on the the object
to be valid when ModalResult is returned. Use caFree
as recommended in XE7 instead,
http://docwiki.embarcadero.com/RADStudio/XE7/en/ShowM
odal_Dialogs_in_Mobile_Platforms.
Comment by Leif Uneus on October 14, 06:25
Delphi XE5 Anonymous ShowModal and Android
Why Dialogs are disabled on Android?
You can emulate it via .ShowModal(procedure XXX)
Comment by Vladimir on November 4, 17:45
Delphi XE5 Anonymous ShowModal and Android
It does not work. The caller proceeds without waiting
for the called form to close
Comment by pedro on November 8, 10:17
Delphi XE5 Anonymous ShowModal and Android
Hi Marco, I ran the code in Rio 10.3, but I have to implement the
OnClose event to assign the ModalResult because the Button's
ModalResult doesn't work. This code is still a good approach to
implement Modal dialogs in Android or is there a new better
approach?
Thanks
Comment by LUIS A. GAMA on April 24, 03:31
Post Your Comment
Click
here for posting
your feedback to this blog.
There are currently 0 pending (unapproved) messages.