Do you want to use FMX dialogs in Delphi applications? Read all about how to do this in this article from Tech Partner Softacom.
How to Use FMX Dialogs Correctly in Delphi Apps
Delphi FMX provides support for customized native dialog boxes (like those used for confirmations and warnings), which are available on all supported target platforms. This article will show the basics and the rules of using these dialogs correctly in your Delphi FMX apps.
What Dialogs Are Available?
There are 3 kinds of native dialogs available in FMX for every OS – Windows, Linux, macOS, iOS, and Android:
- MessageDialog: a dialog box of a special kind (Error, Confirmation, Information, Warning). It contains text and a custom set of buttons, with every button returning a response as an integer to the calling app.
- InputQuery: a dialog box that contains a custom number of text input fields (TEdit controls). This dialog will return an array of strings to the calling app.
- ShowMessage: a simpler dialog box, used only for information with text and an “OK” button. Nothing is returned to the calling app.
Basics of FMX Dialogs
Dialog behavior
According to the platform, dialogs can have two different behaviors:
- Synchronous: the app is blocked by the dialog box until it is closed by the user. This behavior is supported on Windows, MacOS, and iOS. But it is not supported on Android (because the OS does not support blocking of the app’s main thread).
- Asynchronous: the app is not blocked by the dialog box. The app remains accessible for user interactions. This behavior is supported on Windows, MacOS, iOS and Android.
The methods for calling Sync dialogs are functions that return responses to the executing app, while the methods for calling Async dialogs are procedures containing anonymous methods (with the dialog responses as parameters) that are executed when the dialog is closed.
Both behaviors are implemented in FMX platform services.
The actual FMX architecture provides two concepts for using these dialogs, you can choose between:
- Using a platform service from the “FMX.Platform” unit, by declaring an instance of the service interface (as a variable) and the “Supports” routine. Those service interfaces are:
- Or, using the helper class that provides class methods and functions for calling the dialog boxes without the need for an instance of the corresponding dialog box platform service. Those helper classes are:
Dialog type
For the “MessageDialog” kind, you have to define the type of your dialog box, which will affect its appearance. Mostly the title of the dialog box (which is localized to the underlying OS language).
The type of the dialog box is set by a value of “TMsgDlgType”:
TMsgDlgType = (mtWarning, mtError, mtInformation, mtConfirmation, mtCustom);
| Value | Meaning | Dialog box title |
| mtWarning | Warns the user about a potential issue. | Warning |
| mtError | Informs the user of an error that occurred. | Error |
| mtInformation | Provides information to the user. | Information |
| mtConfirmation | Asks the user for confirmation. | Confirm |
| mtCustom | None of the above. | Your project name |
The possible values of “TMsgDlgType”
Dialog box buttons
For the “MessageDialog,” you can choose a set of buttons (their type is “TMsgDlgBtn”) to appear at the MessageDialog bottom. Also, the captions on these buttons are localized according to the OS language.
Each of these buttons, when clicked, will close the dialog box and return a corresponding integer value as “TModalResult”. Because, in fact, the dialog box is a modal form, and setting the value of its TModalResult property to a no-zero integer value will close the modal form.
The returned TModalResult value can be used in the caller app, either assigned directly to a variable (in case of Sync dialogs) or in an anonymous method to perform custom actions after closing the dialog box (in case of Async dialogs).
The table below enumerates the MessageDialog buttons and their corresponding returned ModalResult (as named constants and integers):
| TMsgDlgBtn value | Corresponding returned value | ModalResult corresponding integer value |
| mbOK | mrOk | 1 |
| mbCancel | mrCancel | 2 |
| mbAbort | mrAbort | 3 |
| mbRetry | mrRetry | 4 |
| mbIgnore | mrIgnore | 5 |
| mbYes | mrYes | 6 |
| mbNo | mrNo | 7 |
| mbClose | mrClose | 8 |
| mbHelp | mrHelp | 9 |
| mbAll | mrAll | 12 |
| mbNoToAll | mrNoToAll | 13 |
| mbYesToAll | mrYesToAll | 14 |
Also, the “FMX.Dialogs” unit defines constants that you can use to represent some predefined sets of buttons, as shown in the following table:
| mbYesNo | TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo |
| mbYesNoCancel | TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo, TMsgDlgBtn.mbCancel |
| mbYesAllNoAllCancel | TMsgDlgBtn.mbYes, TMsgDlgBtn.mbYesToAll, TMsgDlgBtn.mbNo, TMsgDlgBtn.mbNoToAll, TMsgDlgBtn.mbCancel |
| mbOKCancel | TMsgDlgBtn.mbOK, TMsgDlgBtn.mbCancel |
| mbAbortRetryIgnore | TMsgDlgBtn.mbAbort, TMsgDlgBtn.mbRetry, TMsgDlgBtn.mbIgnore |
| mbAbortIgnore | TMsgDlgBtn.mbAbort, TMsgDlgBtn.mbIgnore |
How to use the different FireMonkey FMX dialogs?
Now, let’s see how to use each kind of these native dialogs.
What is the difference between the Sync and Async versions of message dialogs in FireMonkey FMX?
There are two versions – “sync” and “async”. The sync version is more like the kind of message dialog that you may have used with VCL apps on Windows. You can read the full details in the Embarcadero DocWiki entry here: https://docwiki.embarcadero.com/Libraries/en/FMX.DialogService.TDialogService.ShowMessage
Briefly, from that page here is an explanation of the differences between Sync and Async:
- On desktop platforms (Windows, macOS, Linux), ShowMessage behaves synchronously. The call finishes only when the user closes the dialog box.
- On mobile platforms (Android and iOS), ShowMessage behaves asynchronously. The call finishes instantaneously, it does not wait for the user to close the dialog box.
How to use the FireMonkey FMX “ShowMessage” version of a dialog
In the simplest kind of dialog, you only need to specify the text that will be shown. The code for calling ShowMessage Async:
procedure TForm1.Button1Click(Sender: TObject);
var
AsyncService: IFMXDialogServiceAsync;
begin
if TPlatformServices.Current.SupportsPlatformService (IFMXDialogServiceAsync, IInterface(AsyncService)) then
begin
AsyncService.ShowMessageAsync(‘This is ShowMessage Async’);
end;
end;
The code for calling ShowMessage Sync:
procedure TForm1.Button1Click(Sender: TObject);
var
SyncService: IFMXDialogServiceSync;
begin
if TPlatformServices.Current.SupportsPlatformService(IFMXDialogServiceSync, IInterface(SyncService)) then
begin
SyncService.ShowMessageSync(‘This is ShowMessage Sync’);
end;
end;
How to use the FireMonkey FMX “MessageDialog” version of a dialog
As explained above, to use MessageDialog you need to specify:
- The message (text of the dialog)
- The dialog type (mtWarning, mtError, mtInformation, mtConfirmation, mtCustom)
- The set of buttons
- The default button will have the initial focus when the dialog is shown
- The help context (0 if no help is used in the app)
For Async MessageDialog, you need, as an additional parameter, an anonymous method to handle the dialog result like the following code snippet:
procedure(const AResult: TModalResult)
begin
case AResult of
mrYES:
Label1.Text := 'YES';
end;
end
But for Sync MessageDialog, the dialog result is returned as an integer from the dialog calling method.
This is how to call MessageDialog Async:
procedure TForm1.Button1Click(Sender: TObject);
var
AsyncService: IFMXDialogServiceAsync;
begin
if TPlatformServices.Current.SupportsPlatformService(IFMXDialogServiceAsync, IInterface(AsyncService)) then
begin
AsyncService.MessageDialogAsync('Question ?', TMsgDlgType.mtConfirmation, [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], TMsgDlgBtn.mbNo, 0,
procedure(const AResult: TModalResult)
begin
case AResult of
mrYES:
Label1.Text := 'YES';
end;
end);
end;
end;
Here’s the code for calling MessageDialog Sync:
procedure TForm1.Button1Click(Sender: TObject);
var
SyncService: IFMXDialogServiceSync;
rValue: integer;
begin
if TPlatformServices.Current.SupportsPlatformService(IFMXDialogServiceSync, IInterface(SyncService)) then
begin
rValue := SyncService.MessageDialogSync('Question ?', TMsgDlgType.mtConfirmation, [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], TMsgDlgBtn.mbNo, 0);
Label1.Text := rValue.ToString;
end;
end;
How to use the FireMonkey FMX “InputQuery” version of a dialog
To use InputQuery, you need to specify:
- The caption of the dialog box.
- The prompt of each input field (a declared variable of an array of strings), and if you want to mask a field as a password, add ‘#1’ before the prompt (like #1 + ‘Password’).
- The values of each input field: A declared variable of an array of strings. It can be filled at runtime (before calling the dialog) to serve as default values.
For Async InputQuery, you need, as an additional parameter, an anonymous method to handle dialog result (clicked button) and the user input values, like the following code snippet:
procedure (const AResult: TModalResult; const AValues: array of string)
begin
case AResult of
mrOk:
Label1.Text := AValues[0] + '/' + AValues[1];
end;
end
But for Sync InputQuery, the dialog calling function returns a boolean value (true if the user clicks the OK button). Then the user input values can be accessed through the Values variable.
The code for calling InputQuery Async:
procedure TForm1.Button1Click(Sender: TObject);
var
AsyncService: IFMXDialogServiceAsync;
caption, inData: array[0..1] of string;
begin
caption[0] := 'Name :';
caption[1] := #1 + 'Pass :'; // Masking function when #1 attached in front
// Setting initial values
inData[0] := 'admin';
inData[1] := '1234';
if TPlatformServices.Current.SupportsPlatformService(IFMXDialogServiceAsync, IInterface(AsyncService)) then
begin
AsyncService.InputQueryAsync('Input login credentials', caption, inData,
procedure (const AResult: TModalResult; const AValues: array of string)
begin
case AResult of
mrOk:
Label1.Text := AValues[0] + '/' + AValues[1];
end;
end);
end;
end;
The code for calling InputQuery Sync:
procedure TForm1.Button1Click(Sender: TObject);
var
SyncService: IFMXDialogServiceSync;
caption, inData: array[0..1] of string;
begin
caption[0] := 'Name :';
caption[1] := #1 + 'Pass :'; // Masking function when #1 attached in front
// Setting initial values
inData[0] := 'admin';
inData[1] := '1234';
if TPlatformServices.Current.SupportsPlatformService(IFMXDialogServiceSync, IInterface(SyncService)) then
begin
if SyncService.InputQuerySync('Input login credentials', caption, inData)
then
Label1.Text := inData[0] + '/' + inData[1];
end;
end;
That’s it! Are you ready to use the power of FireMonkey FMX dialogs in your apps?
Like any other component in the Delphi frameworks, knowing the mechanism and the basics behind native dialogs allows the developer to use them correctly and effectively in their projects.
If you want to try out projects of your own and you don’t have a copy of the latest version of RAD Studio with Delphi, you can go to the products page and download a free fully working trial version.

