paint-brush
Delphi GUI Programming with FireMonkey Framework: Cross-Platform Development Made Easyby@packt
2,547 reads
2,547 reads

Delphi GUI Programming with FireMonkey Framework: Cross-Platform Development Made Easy

by PacktNovember 12th, 2020
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Delphi GUI Programming with FireMonkey Framework: Cross-platform Development Made Easy. We discuss the benefits of FMX and the benefits it provides to developers. FMX is a tool for cross-platform development that lets developers focus on their application code while building fast, good-looking, modern applications for Microsoft Windows. We see FMX as a fantastic tool capable of letting developers build fast and good looking applications for Windows. It may mean that a single development tool is insufficient to accomplish the mission, with a huge impact on the time and cost of deployment.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Delphi GUI Programming with FireMonkey Framework: Cross-Platform Development Made Easy
Packt HackerNoon profile picture

These days, developers face a difficult problem: how to build effective cross-platform applications. From a project management point of view, often a major goal is to achieve this using a single source code base, rather than by having a different code base for each supported platform.

The introduction of the FireMonkey (FMX) framework put Embarcadero Delphi in a magic spot within the global software development scene.

Developers were now able to design and build native applications for the most popular platforms, including both desktop (Microsoft Windows, Linux, and Apple OS X, now also known as macOS) and mobile (Google Android and Apple iOS), using a single toolset and language, thus significantly reducing the effort needed.

Here we say what FMX is, why it was created, and what its great strengths are. By the end you will understand the context in which it was developed and have an appreciation of its underlying philosophy.

The route to FireMonkey

In the 1990s, Delphi was arguably the best development environment to build Microsoft Windows applications. This was the time of Windows 95, when the IT world was much simpler than it is today. DOS and Windows had a very large share of the PC market.

The remaining part of the world was running Linux or Macintosh but with a limited share and only in very specific contexts. Even though the mainframe (such as IBM AS400) was still a thing, businesses were mostly running Windows.

Developers who were keen to build Windows GUI applications had a variety of languages at their disposal, including Visual Basic, Java, and Visual C++, but Delphi soon earned a loyal following.

The ability to easily build beautiful standalone Windows applications via a slick IDE was a great plus and was one of the key factors behind Delphi's success. 

Apart from the convenient GUI-centred Rapid Application Development (RAD) approach, built into an effective IDE, Object Pascal was a great language, showcasing full Object-Oriented Programming (OOP) support, great C compatibility (perfect for Windows API calls), and featuring a very fast compiler.

Generated applications also had outstanding runtime performance. 

Looking at Delphi as a whole product, we see a fantastic tool capable of letting developers focus on their application code while building fast, good-looking, modern applications for Microsoft Windows.

The product was more abstracted than raw C/C++ programming and proved to be way more powerful than Visual Basic (to mention two of the biggest Delphi competitors).

All this was possible thanks to a framework shipped with the product: the Visual Component Library (VCL). It acted as a sort of abstraction over the standard Windows controls, wrapping them in a more suitable and easy-to-use programming interface.

A big difference with respect to other products is that this has provided the ability to go back to being low-level and interact with the primitive control whenever needed.

Every Delphi developer felt at home while dealing with VCL components and most applications never needed to descend into low-level code. This meant higher productivity for the developer. 

Today’s technology environment is more complex than that of the late 1990s. We have seen the rise of mobile platforms, with Android now the most heavily used OS worldwide.

Also, the desktop platform scene has evolved, with Apple’s Mac OS X (aka macOS) enjoying greater adoption than before (even if this is not equally true in every part of the world). In the following figure, you can see OS distribution over time (period starting January 2009 to January 2020 – data source: https://gs. statcounter.com):

Figure 1

Readily apparent are the decline of Windows (the dominant platform from 2009 to 2017) and the corresponding rise of Android (overtaking Windows around 2018).

Today, multi-tier architectures have become the de facto standard for real projects that have to deal with a (possibly high) number of heterogeneous clients and provide users with proper interfaces in a range of scenarios (desktop, mobile, web platforms across different device families).

This makes it increasingly challenging to see applications as single projects built for a specific platform. The requirement for an application to be available across multiple platforms is very demanding, yet is now almost standard. 

Meeting these requirements is hard because developers must learn platform-specific behaviors, technologies, APIs, programming languages and deployment toolchains.

It may mean that a single development team is insufficient to accomplish the mission.

All this can lead to maintainability issues, with a potentially huge impact on the total cost and time-to-market of the product you are building. But if building a specific application for each platform sounds expensive, the other option (to build a single cross-platform application) also has issues to address.

First, nobody wants a cross-platform application framework that only allows the developer to work with the common features shared by all the platforms.

This approach would fall short, since platforms are diverging in terms of functionalities and even the capabilities available on all platforms usually have some interface/implementation details that make them hard (or expensive/inefficient) to abstract.

At the same time, nobody needs a framework composed of specific functionalities gathered from all supported platforms, since this would result in something enabling developers to build applications utilizing the functionalities of all platforms but forcing them to write different code (in the same language, though) for each platform.

The solution (as often happens) is something situated between these two opposites. FireMonkey adopts a mixed strategy which, being a sort of compromise, translates into a list of strengths and weaknesses. 

In the following screenshot, you can see the Delphi IDE while designing a multi-platform application.

The Android style is selected for use in the form designer, an iOS style preview is available through the Multi-Device Preview window (docked into the IDE on the right side) and an instance of the application is running on the Windows platform, just in front of the IDE itself.

Thus we have three styles visible at the same time, one per platform; three different binaries using the same (single) source code:

Figure 2

This screenshot encapsulates how easy it is to build your application for multiple platforms, using a single programming language: Delphi. You can design your app in the IDE, select one of the supported styles (each style being associated with a specific platform—Android, as shown in the previous screenshot) to preview the result in the form designer, seamlessly.

At the same time, you can also have a look at Multi-Device Preview (part of the IDE set of functionalities named Fire UI). There, you see a realistic preview of how your application will look on other (multiple, eventually) platforms (iOS, which is also shown in the preceding screenshot).

Note that neither of the two mentioned platforms (Android and iOS) is the one that the IDE is running on (Windows) and that your app will also be able to be executed, no code changes needed, on Windows (and Linux and OS X/macOS).

If that doesn't sound great enough then you can go even further and have your forms previewed, live, on a mobile device through another technology named Live Preview (still part of the Fire UI set, http://docwiki.embarcadero.com/RADStudio/en/FireUI_Live_Preview).

This time, you'll be able to preview (without having to wait until the compilation time) your UI on actual physical devices, without effort, with the screen of the device acting as an extension of your IDE.

Now let’s look in a little more depth at the strategy FMX takes in order to provide different UI visuals to match the current platform of the running application.

Abstracting app visuals

The first version of the FMX framework was released in 2011 and already demonstrated one of its fundamental features: rendering of the UI from scratch, using the GPU. At the time, the GPU already supported technologies such as shaders (https://en. wikipedia.org/wiki/Shader), opening up a way to implement high-quality vector graphics, taking into account the growth of CPU power.

It became possible to build complex UIs, decorated with stunning effects and transitions, having the same appealing visuals typical of technologies such as Flash (the leading technology in modern and good-looking UIs at that time).

Given that WinAPI (and thus the VCL) and the new (at that time) .NET alternative – Windows Presentation Foundation (WPF) – were not offering such capabilities, the development team of FMX saw a great opportunity to build a new framework. 

This was the beginning of the framework having the opportunity to control every aspect of the UI implementation, creating the possibility of strongly abstracting the UI from platform-specific controls and capabilities.

However, the number of controls available was limited and the first version of FMX was unable to provide the same level of functionalities offered by the VCL on Windows.

The major new feature added with FMX 2 was bitmap styles: building a rich vector-based UI had a huge impact on performance and, at the same time, it was hard to implement some of the required components and peculiarities of the UIs.

Adding the bitmap style capability moved FMX into the position to build effective, good-looking (pixel-perfect was the motto at the time), and performant applications, while retaining strong abstraction (through the style concept).

Even though it may seem a step backward (from pure vectors to bitmap styles), remember that the evolution of computer graphics over the decades has seen bitmaps come to play a central role.

Hence most operating systems and drawing technologies are very familiar with bitmap (raster image) handling and have been optimized for that.

The FMX framework is an application framework rather than a merely visual framework, however.

While the general approach toward cross-platform application development has much to do with the visuals (we are focusing on visual applications, after all), there's much more to consider.

Looking beyond the UI

Even though many current prototyping tools tend to see an application as a bunch of views, we all know that any real application is not made only of a set of mere visual assets.

Your visual application framework (FMX in the case) must also provide actual functionalities, and you will need some level of interaction with the platform the application is running on.

Modern application functionalities include some that are basic, such as (multi-)touch support, and interaction with the system clipboard or with the filesystem, as well as more specific functionalities such as sensor integration (camera and positioning, for example) or other device-specifics such as notification systems, voice recognition, text-to-speech, and other advanced capabilities.

Such requirements mean that FMX (and the Delphi RTL parts added by Embarcadero in recent years, available both for FMX and VCL) is much more than a visual framework, providing powerful abstractions that a developer can use to implement functionalities in a real cross-platform way.

Just as a simple example, iOS and Android use different file formats for audio and video, thus to have a single TMediaPlayer component leveraging this difference is very convenient for the developer, who just has to ask the component to play or record audio/video with the same code.

Accessing the storage of the device (the camera roll for iOS or the Gallery/Photos apps for Android) is another great example. 

You may think that access to such abstracted functionalities represents a veritable playground for the app developer, but this is only partly true. The VCL has a great level of abstraction over most Windows controls and APIs, but you always have the chance to go back to the metal.

In other words, you can sidestep the generally convenient abstraction of the VCL and tweak your code, adding low-level Windows API calls (without confining your possibilities to what the framework offers).

This is also possible in the FMX framework, as we shall see in the next section.

Back to the metal

Strong abstraction can easily become a golden cage for its user. This also applies to software development and frameworks. Obviously, you like the fact the framework is hiding the complexity underneath and providing a simple, clean, and comfortable place where the developer can live with fewer worries as compared with a more raw approach where everything is the developer's responsibility.

But at the same time, this kind of safe playground (always) has some boundaries, and the developer can sometimes reach one of these boundaries and need to go further.

Delphi always shone in this, letting you stay warm and safe with your VCL components wrapping Windows controls but, at the same time, letting you directly call whatever external functions were available, including, of course, all WinAPI functions.

When coming to FMX, you should think of it too as not just a visual framework but rather an application framework, and this is still true because even if you can’t handle FMX controls using APIs designed for native controls, you can still have your FMX (and RTL) Delphi code make use of platform-specific calls to the underlying APIs of the currently running OS. 

This means that from your Delphi code you can call any iOS library functions (as you would do in Objective-C or Swift).

The same applies to Android where you can wrap – the Java2OP tool is available for Embarcadero’s registered users – the Java code you want to reach into Delphi classes and functions and have it available for your application developer.

Even though this may seem like a kind of last refuge for the developer, it also represents a guarantee that your framework (FMX) is not closed and you are actually able to get back to the metal as much as you like or need.

For example, it is not unusual when writing Android apps on custom devices (that is, those including industrial-level optical or NFC/RFID readers) to have the manufacturer of the device provide it with a standard Android OS image with the addition of some external JAR files with the libraries needed to properly interface with some device-specific features.

Also, it guarantees that if Embarcadero does not provide you with this or that API wrapper, you may proceed and generate it (manually or with a tool such as Java2OP) without having to wait for official support for that functionality.

Understanding FMX’s strengths and weaknesses

Not the least of FMX’s advantages is the continuity it provides. Experienced Delphi (VCL) developers can reuse part of their knowledge and experience while moving from a single (very specifically, Windows) platform development environment to a multi-platform (and/or cross-platform). 

Then there is the fundamental point that a single tool is available that abstracts functionalities to allow it to target multiple platforms, obviating the need for multiple toolsets.

As an example of an area where this approach shines, think about the data access components (and their knowledge) you can naturally use within applications of both the FMX and VCL frameworks.

Virtually every business application has some data-centric part somewhere (often, the most relevant one). 

Another strength of FMX is the possibility to add support for new platforms on the go. Just before the Apple iPhone launched in 2007, nobody would have guessed that Nokia’s Symbian OS would become a dead platform so quickly.

The story of Microsoft mobile operating systems has been characterized by much change and several major bumps. And while today we might reasonably think of the mobile world as being split between Android and iOS, we should be alert to the possibility that a new platform may arise tomorrow.

Similarly, even though it is not really a new platform, the recent addition of Linux as a target platform for FMX GUI applications has been seen as a new conquest by the whole Delphi community.

This addition has been possible thanks to the work of a third-party vendor named KSDev (involving original FMX authors Eugene Kryukov and Alexey Sharagin) and the efforts of Embarcadero to deliver a new compiler for the Linux (Intel) platform.

Together with the LLVM compiler technology, it is the inner architecture of the FireMonkey framework that is responsible for this accomplishment.

Today it puts Delphi in a position to build effective UI applications on up to five different platforms: Microsoft Windows (32-bit and 64-bit), Apple OS X, Apple iOS (and its simulator), Google Android, and Linux (Ubuntu and RedHat are officially supported by the compiler).

From a strategic point of view, knowing that the set of tools your IDE uses to actually build your applications is extensible (from the compiler to the UIs, including RTL and main DAC libraries) has considerable value, especially if you are building large applications or you have an estimated lifespan for your projects of more than a couple of years.

Of course, there are also drawbacks, as there always are, especially in a demanding and dynamic environment involving moving targets (such as mobile platforms). The first obstacle is caused by the high-level abstraction described earlier.

That is, Embarcadero’s whole cross-platform solution is made of abstractions of services and functionalities, with the construction of the UI central to the user experience.

The key strengths of FMX (such as styles and the ability to perfectly mimic a native application's visual and interactive pattern fundamentals) should strongly mitigate the distance from the top of the abstraction and the bare metal on the ground, but it remains a challenge.

The speed of innovation, especially in mobile platforms, we witness today can be hard to integrate into a highly abstracted framework. Embarcadero has opportunities to solve (or at least mitigate) these problems and the first example in this direction has been the introduction of the ControlStyle property, with the platform option to let FMX use a corresponding native control where the developer decides it is worth doing so.

This means that if the underlying OS has some advanced features (think about a device-wide orthographic corrector or an advanced dictation system) built into native controls, even cross-platform applications built-in FMX can rely on them and not lag behind other apps.

In the same arena, relatively young mobile platforms are continuously striving to improve their performance, and so the FMX framework (and Embarcadero’s ecosystem of technologies) will have to constantly evolve to keep pace with native (i.e. non-cross-platform) applications.

Summing up

The FireMonkey framework leverages Delphi’s deep and highly evolved capabilities as a development platform for Windows to apply them to the creation of the kinds of cross-platform solutions now increasingly demanded by users and businesses. The approach adopted is a hybrid one.

There is an extensive abstraction of key functionalities, notably (but not just) in the UI area, but at the same time developers are given the option of switching in native functionality should the particular use case demand it.