Mimicking MessageDlg on mobile platforms
This blog post will describe one of the ways to mimic the behaviour of a MessageDlg, or any other modal form for that matter, in Delphi when running on a mobile device.
Mobile devices, or more correctly the OS running on the mobile device won't allow blocking code, so the traditional Delphi approach of reading a result from a MessageDlg before continuing won't work.
There different ways of getting the desired behaviour, and this describes one way.
Start a new Firemonkey application, drop a button to call up the dialog, and an editbox, that we can display the user's choice in (I have chosen the Android Style, the same of course applies to iOS).
Now create a new form, name it frmDlg and follow these steps:
1. Drop a TLayout on the form, align to Client, name it layoutDlg
2. Drop a TRectangle on the Layout, align to Client, name it recBackground
3. Set the recBackground.Fill.Color to black
4. Set the recBackground.Opacity to 0.5
5. Set the recBackground.Sides to false (all of the four sides)
Your form now looks very boring
Continue to follow the steps
1. Drop another TRectangle on the form, name it recFront and set the alignment to VertCenter
2. Set recFront.Margins.Left and Right to 30
3. Remove the sides, as you did with recBack
4. Set recFront.XRadius and YRadius to 6
Your dialog mimic is starting to take shape, and should look something like
Note that both rectangles have the Layout as parent.
Moving on, there are a few more steps.
1. On recFront drop a TShadowEffect, shadowDlg
2. Set the ShadowDlg.Distance to 5
3. Set the ShadowDlg.Softness to 0.2
Make sure the shadow is on the recFront (recFront is parent)
Let’s make the dialog rectangle just a little better
1. Set the recFront.Fill.Kind to Gradient
2. Double-Click the recFront.Fill.Gradient property to get the property editor running
Cl click the left dot of the two dots at the bottom of the disgner
Set its RGB values as shown in the picture
2. Click the right one and set its to 255 (all of them), this is white
Now we just need a few components on the recFront and the GUI is done
3. Drop a TLabel named lblMessage on the recFront, recFront is parent
4. lblMessage.Align should be Top
5. lblMessage.Margins.Top is 30, left and right are 10
6. lblMessage.TextSettings.HorzAlign is Center
7. lblMessage.TextSettings.WordWrap should be true
8. lblMessage.Height is 60
9. Drop a TLayout on recFront, name it layoutBottom (recFront is parent)
10. layoutBottom.align is set to Bottom
11. On layoutBottom drop two buttons, named btnOK and btnCancel
12. btnOK.align is left, margins.left set to 5, and Text is ‘OK’
13. btnCancel.align is right, margins.right set to 5, and Text is ‘Cancel’
You should now have a form looking similar to my form below
With the structure pane reflecting the parenting of the components
Now we need to implement some code on this dialog. The object is to
1. Display the dialog
2. Having a text in the label
3. And detect if the user clicked Ok or Cancel
To do so, I want the calling code to be as simple as possible, now we cannot have blocking code, so we cannot have a function waiting to return the user choice back to the main form. Let’s start with just displaying the form, adding the other bullets later.
Remember you put everything on layoutDlg, well there was a reason for that. It is possible to move a layout from one form to another, so that’s what we are going to do in the procedure that starts the dialog.
So we create a procedure on the form with the dialog as I did above, remember to make it a public procedure.
To call this procedure from the main form, just use the dlgForm, and call it on the buttons OnClick eventhandler
And this will bring our dialog up very nicely, with the text in the label. Now we need to react to the two buttons OnClick Events, but we of course need to do this from the main form.
To do so, there are different ways. We need to have a couple of events on the dialog. In the private section of the "modal" form define two events of type TNotifyEvent
Expand your procedure to
And on the OK, and cancel buttons OnClick Eventhandlers write the following code
You could also have public properties for those events, in which case your public section of the dialog form would appear as
Now, to call the dialog from your main form, you pass in two procedures with the signature matching a TNotifyEvent: Procedure Form1.procedureName(sender : TObject); I have defined in my example these two
Now, when you on the main forms buttons OnClick eventhandler have this
Your dialog appears nicely