Have an amazing solution built in RAD Studio? Let us know. Looking for discounts? Visit our Special Offers page!
CodeDelphiFireMonkeyWindows

How to Use FMX Dialogs Correctly in Delphi Apps

How to Use FMX Dialogs Correctly in Delphi Apps

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);
ValueMeaningDialog box title
mtWarningWarns the user about a potential issue.Warning
mtErrorInforms the user of an error that occurred.Error
mtInformationProvides information to the user.Information
mtConfirmationAsks the user for confirmation.Confirm
mtCustomNone 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 valueCorresponding returned valueModalResult corresponding integer value
mbOKmrOk1
mbCancelmrCancel2
mbAbortmrAbort3
mbRetrymrRetry4
mbIgnoremrIgnore5
mbYesmrYes6
mbNomrNo7
mbClosemrClose8
mbHelpmrHelp9
mbAllmrAll12
mbNoToAllmrNoToAll13
mbYesToAllmrYesToAll14

Also, the “FMX.Dialogs” unit defines constants that you can use to represent some predefined sets of buttons, as shown in the following table:

mbYesNoTMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo
mbYesNoCancelTMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo, TMsgDlgBtn.mbCancel
mbYesAllNoAllCancelTMsgDlgBtn.mbYes, TMsgDlgBtn.mbYesToAll, TMsgDlgBtn.mbNo, TMsgDlgBtn.mbNoToAll, TMsgDlgBtn.mbCancel
mbOKCancelTMsgDlgBtn.mbOK, TMsgDlgBtn.mbCancel
mbAbortRetryIgnoreTMsgDlgBtn.mbAbort, TMsgDlgBtn.mbRetry, TMsgDlgBtn.mbIgnore
mbAbortIgnoreTMsgDlgBtn.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.


Not a Hotdog How to Use AI Object Recognition in Your Apps   Delphi icon

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.

 

RAD Studio 13.1 Florence Now Available See What's New in RAD Studio 13.1 Delphi is 31 - Webinar Replay

Reduce development time and get to market faster with RAD Studio, Delphi, or C++Builder.
Design. Code. Compile. Deploy.

Start Free Trial   Upgrade Today

   Free Delphi Community Edition   Free C++Builder Community Edition

6 Comments

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

IN THE ARTICLES