Table of Contents
Before you read: Due to rather random set of events, this article started an internet food fight as it reached the first spot on common programming link aggregators.
Some agreed, some complained, some ranted how it doesn’t go into details and I have no idea what I am writing about. Well, you are not wrong on the last part and it wasn’t really meant to be a deep dive into everything under the sun. It’s just my opinion/observation on what is out there, as I couldn’t find such article when I had to pick the technology behind my app.
So here is my proposition. If you heavily disagree with what is written here, please write your own post and educate us all on this topic. I would really like to read it, as there is simply not much content on programming desktop applications. Even the basic tutorials are sometimes hard to find.
These discussions that formed around this article were invaluable for me, and the only way to keep these discussions going is to write more content, written by experts like you.
Also read the notes section before commenting. Half of the comments were mentioning things that were tackled and explained in the notes section.
As I was recently deciding (where recently means years ago) on the technology behind the SlothTracker - a cross platform time tracker, I thought I would reflect on the past and write a few words on the topic of cross platform desktop development.
When confronted with question why their application needs a constant internet connection and can’t be running locally, they turn to their savior - the mighty Electron. With some clever copy and paste tricks their web application is now running as a desktop application that is consuming only 500MB of RAM. It’s a reasonable price to pay if we take in consideration that they are displaying 2 text fields and 4 buttons in their favorite color. RAM is cheap and everyone has enough of it nowadays, while a large majority of consumer laptops are still shipping with 4GBs of RAM.
Still there has to be a reason why everyone seems to be writing web applications these days.
Current state of cross platform GUI frameworks
In the parlance of our times where every great idea that somebody has was already taken and developed at least 10 years ago, you still hope to get some crumbs in the long tail of your chosen market.
To stand out in the crowded market and make sure that people may keep using their favorite programs as they switch the walled gardens that we call operating systems nowadays, you would like to develop an application that works on all three major platforms (Windows, Mac and Linux).
As not everyone has the resources to rewrite the same application multiple times in the operating system’s specific toolkit, you reach out for the cross platform GUI framework. There are tons of them out there surely there is something in it for you?
Here is the list of somewhat popular GUI frameworks which are sort of usable in the languages specified in the parentheses :
- Qt (C++)
- Gtk (C, C++)
- WxWidgets (C++)
- JavaFX (Java)
- Lazarus (Pascal)
I am not trying to claim the expertise in every GUI framework listed above, but due to unpredictable life events I happened to try every single one of them at least to the point to form an opinion. So everything below this line is my personal opinion about the current state of things in this wacky world of desktop application development.
Qt is currently the most popular cross platform GUI framework on the market. It’s mainly used with C++ although bindings for other languages exists as well (Python).
For programming in Qt it is recommended to use QtCreator IDE which contains both an editor and a RAD tool. The QtCreator’s editor itself is not as good in comparison to IDEs of other languages (such as Intellij) especially when it comes to refactoring tools. For writing C++ it is still the best free editor on the market. It has a decent autocomplete and “IntelliSense” like features if you enable the builtin Clang checker. As long as you don’t write complicated templates it works quite okay.
I don’t really like the QtCreator’s RAD tool as the GUI layout in the RAD tool often looks quite different from the layout that you see once you compile and start the app. I often had to use “spacer” elements in order to push certain GUI components into their desired positions of their parent container. This felt quite weird as it seems to be the only RAD tool that is using these kinds of tricks for laying out GUI components.
Every now and then you discover that certain properties of the GUI component are not settable through the RAD tool and you have to tweak them directly in the code. Not a big deal, but I personally found this quite annoying as you never know whether or not you have some hidden property set in the code.
The compile times are especially awful on large applications even with incremental compilation. While working on a larger project, I remember developers waiting for a minute on every change in a specific widget. A C++ enthusiast is probably chanting “PIMPL” right now, but I would prefer to focus on writing the business logic of my GUI instead of performing weird rituals around the programming language limitations.
Apart from the problems described above, the Qt itself seems to be quite well done and feature complete.
Documentation is well written and there are a lot of tutorials, books and questions and answers on the internet. You will most likely find the answer on your question due to sheer size of the Qt community.
Qt comes with a large number of GUI components. Buttons, comboboxes, text fields, search fields, tables,… are all present in Qt.
The performance of the Qt application is great even on older computers. The final application size is small enough (well that depends on which Qt parts your application is including). Still better than Electron.
You can change the look and fell of your application with QSS (Qt specific CSS like “language”). By default the applications mimic the native look (at least on Windows and Mac), but you can tweak that with QSS files.
If are hiring you will have far greater chance of finding someone who knows Qt as it became the go to choice for writing desktop applications.
Qt website is one big clusterfuck of corporate bullshit and hard to find stuff. They keep redesigning it and every year its getting worse and worse. It’s impossible to find relevant information for your questions and your best bet is relying on the search engine.
Some developers don’t like the Qt’s MOC (Meta Object Compiler) that is used for signals and slots. I don’t have an opinion about that. C++ lacks introspection features and sometimes you have to create a workarounds with such code generation nonsense.
Chart components are missing. This entirely depends on the field you are working in, but I often find myself adding a chart to the application. Charts are not part of the Qt and you have to find the library that does this for you. Make sure to check their licenses as they are often under GPL license, and you have to buy commercial license if you don’t want to release the source code of your app.
C++ programming language. After trying different things over the years, I can dare to say that C++ is a terrible language when it comes to writing GUIs. Instead of focusing on the problem that your GUI is trying to solve you find yourself performing workarounds around the language quirks (e.g: string split is still missing from the standard library in 2020). A grizzled C++ veteran will probably scoff at this statement while carefully copying his string split implementation from the previous project .
Qt is available under LGPL license which allows you statically linking your application only if you comply with the following conditions (copied from GPL FAQ).
For the purpose of complying with the LGPL (any extant version: v2, v2.1 or v3):
(1) If you statically link against an LGPLed library, you must also provide your application in an object (not necessarily source) format, so that a user has the opportunity to modify the library and relink the application.
(2) If you dynamically link against an LGPLed library already present on the user’s computer, you need not convey the library’s source. On the other hand, if you yourself convey the executable LGPLed library along with your application, whether linked with statically or dynamically, you must also convey the library’s sources, in one of the ways for which the LGPL provides.
In other words if you statically link your app, you also have to provide your app in an object format. To me that seems just unnecessary extra work to satisfy the law. Sure you can relink your app with another version of Qt, but who is really going to do that?
I personally prefer statically linked blobs over the mess that is caused with shared libraries. You can always buy a commercial license that gives you the rights to statically link your application but it comes with a hefty price (if you are even able to find that information on their shoddy website).
GTK is the GUI framework used by Gnome (Linux). According to their website, they claim that the framework is cross platform although apart from Gimp, I haven’t seen many notable applications written in it.
While Vala seems to have some nice improvements over C, I don’t really understand why they invented a whole new language in order to get what? Another layer of abstraction to get poor man’s C++. For the uninitiated reading this, Vala first generates C code and that C code is later compiled with a C compiler. So when it’s time to debug your application you have to debug the generated C code. That must be loads of fun.
I would really like to understand the reasoning behind promoting Vala instead of C++, but even after spending some time searching around I didn’t really find anything worth mentioning. My best guess would be that people like to spend time tinkering with interesting things in their free time. Writing a new programming language is loads of fun. Writing C++ is not.
The recommended RAD tool for GTK is called Glade. I had a great experience with it in the past as it was quite intuitive to use. I am sure it contains some nasty bugs, but I simply wasn’t using it long enough to be able to discover them.
The GTK framework is “painting” the GUI elements on the screen and you can style them however you like with a CSS. In the beginning it was expected that every platform will have its own stylesheet that will mimic the look and feel of the platform in a similar way to what the Qt is doing. That didn’t quite work out.
My past experience with the GTK could be summed in: “It is a big mess”. The Windows builds were non existing (due to lack of volunteers as most users were Linux users), nobody used it on the Mac either and the entire GTK website was one big hodge podge of “stuff”.
The documentation was “there” if you were a C programmer and for rest of the languages you had to rely on the good will of your search engine of choice. Beyond the basic examples there were no in depth tutorials or books to learn from. In the documentation section of the GTK website, there were a whole lot of 5 tutorials and 3 books. 2 of those books were 10+ years old and the other one was not really a book but more like a few tutorials in German posted somewhere on a dusty wiki page.
When I was looking at open issues online to see what is going on with the project, this was the first issue I was able to find on their public issue tracker:
Question: Caret not shown on empty GtkEntry using win32 theme
Answer: Win32 theme is an unsupported mess (as in, there’s literally zero people willing to work on it). Just saying. There’s a reason why Adwaita is the new default.
So I guess, if you want to see the Adwaita theme with its toddler’s sized buttons and bad UI decisions on every platform and not just on Linux, I guess you could use it.
Obviously the thing never got popular outside the Linux ecosystem, due to the lack of corporate backing. Searching for GTK jobs on the StackOverflow found exactly 0 hits. I mean who in their right mind is going to bet their future on such a pile of wacky stuff that is the GTK world.
Glade RAD tool is quite intuitive and easy to use in comparison to other RADs that I have tried.
You can completely customize the look and feel of your GUI with CSS.
I don’t really see any other pros to be honest. If you like writing GUIs in plain C then maybe.
According to Wikipedia’s criticism section for GTK:
The most common criticism of GTK is the lack of backward-compatibility in major updates, most notably in the application programming interface (API) and theming.
There are not really many tutorials or books written about GTK. All of them are 10+ years old and outdated.
GTK is not really used outside of the Linux platform. If you are hiring you might have a hard time finding GTK developers as the framework is not really popular.
WxWidgets is a cross platform GUI framework written in C++. Apart from writing your application in C++ you can also use the bindings for other programming languages like Python (wxPython). The idea behind the WxWidgets is to give you an easy to use API that would work the same on multiple platforms while maintaining native look and feel. Since the framework is making native calls for displaying the widgets you cannot really style your application like in the other non native GUI frameworks which may or may not be desired.
There is a big draw back though. They expect people to build their GUI with code. In order to put your buttons on the screen, you basically have to knock out C++ code and write your entire layout that way. Every time you change some padding in your code, you will have to wait for the code to compile and launch. Since C++ is not really known for its fast compile times, you may find yourself waiting for the damn thing to compile more often than actually writing your code.
You can find a RAD tool for WxWidgets called WxFormBuilder, which allows you to drag and drop widgets on the screen and the tool spits out the C++ layout code for you. The whole thing is a big mess as you have to figure out how to wire your application logic to the ever changing layout file. Button clicks are wired in the layout file, which is regenerated every time you change the layout (and that would wipe out your business logic). You can create a subclass that extends the generated layout class and put all your logic there. It’s quite ridiculous when you think about this that such a simple behavior already needs workarounds.
The RAD tool itself is only half way done and is actually quite terrible to use. There are at least 3 different RAD tools on the market (some even commercial), but I didn’t really like any of them.
My experience with WxWidgets comes from writing a small image viewer utility. I had a lot of issues with it mostly due to the lack of tutorials and best practices on the internet. The latest book on WxWidgets was released 15 years ago. The documentation is decent but you often have to dive into the source to figure out the behavior of a certain widget.
The awful compile times for every simple GUI layout change broke the camel’s back and made me leave this GUI framework for good. No the RAD tool is not good enough to be deemed usable.
Native look and feel.
Great performance and small application size.
GUI components seems to be well documented.
LGPL license with an exception stating that derived works in binary form may be distributed on user’s own terms. Which as far as I understand this, you can actually statically link your app without distributing the sources. I am not a lawyer though so make sure to double check if that is really so.
Tutorials are hard to find. Books are all outdated (15+ years old). “You live and you learn” seems to be your only option when it comes to learning WxWidgets.
Writing GUI layout in C++ code. WxFormBuilder RAD tool feels like a half done software in comparison to RAD tools of other frameworks.
It’s not really popular. I don’t think I have met anyone that would know or be actively developing in WxWidgets so far. I guess you would have a hard time finding the hiring the developers.
Out of listed GUI frameworks, JavaFX is the one I have the most experience in. It was also the framework chosen for the development of SlothTracker - cross platform time tracker, simply because it was relatively easy to deploy on multiple platforms.
The look and feel of JavaFX application could be completely customized with a CSS like language and the tooling is great as the framework is based on Java and you get the access to the wealth of the Java ecosystem. The UI iteration times are way better than with any of the C++ based frameworks that I had tried so far.
The RAD tool is a separate standalone software called Scene Builder, which is sort of usable for a rough layout of your GUI. You can drag and drop GUI elements on the panels which are later saved as FXML files and could be loaded within your source code. If you are using Intellij the SceneBuilder is already integrated in the IDE and you can switch between FXML or RAD tool with one click.
The problem with the SceneBuilder is that the final layout might look a bit different since certain CSS styles could be inherited from your global css file only when your application initializes. I usually create a rough layout with SceneBuilder for a specific GUI component and later tweak it within the FXML file.
For inspecting the actual layout of the running application you can use ScenicView which works in the same way as the dev console in your browser. You can select the elements and it will list all the properties that the selected element has (paddings, margins, alignments, etc…). You can tweak CSS files while the ScenicView is running and the CSS styles will be automatically reloaded which saves you a lot of time.
With JDK 14 you can create native installers by running the new jpackage command. If you specify the needed JDK dependencies the jpackage will create an installer containing your jar and stripped down JRE. For a smaller applications such as SlothTracker the installer size sits at 45MB.
Great development environment due to Java programming language. People like to complain about Java’s verbosity, but the tooling alone simply blows away every other programming language.
Documentation is well written and there are plenty tutorials and books written about JavaFX. StackOverflow contains a lot of questions and answers about JavaFX.
Charts are part of the standard GUI components, but they are not that feature complete. I have often found myself wanting a feature that didn’t exist and had to write my own workaround for it.
Works on Windows, Mac and Linux with almost no changes necessary. I was able to run the same application on all platforms and it worked without tweaking anything.
Installers that contain your app and JRE are easy to create with jpackage tool coming with JDK 14.
The look and feel is quite easy to customize via their CSS like language.
The JavaFX developers were drinking from the OOP fountain a bit too much (OOP - Object Oriented Programming). There are long inheritance chains with useful member variables that you just happen to need that were turned into private final ones. Finding a workarounds to get the access to those private fields without copying the entire implementation into your own code could be a tiring process. Not everything has to be hidden from the end user, you know?
The support for tables is downright awful. Until JavaFX 14 you couldn’t automatically resize the table column based on the width of the text in the column. The table itself contained the logic for that, but it was hidden in one of the package private classes and the only way to trigger that logic, was to either copy and paste the code or trigger the method via reflection.
Bugs or missing features. Despite its age and well done API in some areas JavaFX still feels like it is in an alpha stage. There are plenty of missing features - like poor multi monitor support or bold system fonts missing on MacOs. It’s easy to put some buttons on the screen but once you need polished features you often have to roll up your sleeves and find a workarounds.
Their way of writing CSS for the GUI components feels a bit weird. Almost everything is styled by using multiple backgrounds and insets. So they specify 4 different backgrounds and set the offsets of those backgrounds in a way that the correct background is being displayed at their necessary position. That means that border of your GUI component is actually a background that is visible through the rest of the backgrounds and when overriding default styles you have to play around with backgrounds to figure out which layer is doing what.
Because Java is running in a virtual machine, the start up times are a bit slow. In comparison to native frameworks, the memory consumption is not that great either. The SlothTracker is currently running at ~220MB of RAM, depending on the platform. Not quite Electron worthy, but still something to pay attention to. Opening or resizing a large dialog feels a bit sluggish in comparison to other native GUI frameworks.
SceneBuilder RAD tool could be better. It’s a bit buggy (especially when dealing with grids) and dropping elements on the screens feels unnecessarily slow.
According to their website, Lazarus is a Delphi compatible cross-platform IDE for Rapid Application Development. It strives to be free and open source replacement for Delphi.
Before writing this review, I have never written a line of Pascal, but after playing around with the IDE, I managed to create a simple todo application. Pascal doesn’t really seem to be a hard language to learn. After all it was designed for teaching good programming practices.
The IDE is quite rough around the edges when compared to something like Intellij. There does not seem to be any “IntelliSense” like features that would suggest you code improvements as you type. Once you are used to a luxury like that, it just feels weird going back to the roots and “fighting” the compiler again. Lazarus IDE also has embedded RAD tool which allows to drag and drop elements on the screen and it actually works quite okay. I am also quite sure that it has some nasty issues, which I was not able to discover due to my limited exposure to the Lazarus ecosystem.
For specifying the GUI layout I was expecting some kind of vertical and horizontal containers as that is how the components are usually laid out in other RAD tools. Apparently in the Lazarus world everything is being done with panels and anchoring. Once you figure out how the anchoring works, you can do pretty much anything you want, but it’s not really that intuitive. A big bonus for Lazarus is also native look and feel out of the box.
People claim that Pascal is compiling fast, but that does not seem to be the case with Lazarus. My totally unscientific method of watching the clock while checking the console window told me that the compilation is fast but a lot of time is wasted on linking. I have found myself waiting for the application to appear on the screen for ~7 seconds every time I pressed the run button. You can find videos on the internet where the application seems to recompile and start instantly, so there may be some configuration issues with my environment.
The good thing is the compiled binaries are statically linked by default and quite small. On Linux a simple application that contains a window and a few buttons stands at 5.4MB and it consumes 10MB of memory.
The main problem I see with Lazarus is that Pascal went out of fashion years ago. There are not really many tutorials or books for Lazarus so the only way to learn the framework is by figuring it out on your own, which makes for a far slower learning curve. Maybe the Delphi developers will feel right at home but I can’t really say as I never touched Delphi either.
Searching for Pascal/Delphi jobs on StackOverflow found exactly 0 jobs. That’s not a great indicator and Pascal is probably not such a hot investment that one working as a programmer would make. Despite all the drawbacks described above, I was pleasantly surprised that the Lazarus is quite usable and I wouldn’t mind writing smaller GUI utilities in it.
Native GUI components and therefore great app performance.
Small application size.
A relatively large library of GUI components (charts are included).
No messing with the build scripts. You just open the project file and start writing code.
Well done RAD tool. It’s one of the more polished ones that I had tried so far.
Pascal is showing its age and feels a bit wonky in comparison to C like languages. I just prefer to write brackets over begin ends everywhere.
Documentation is sparse. The tutorials are rare I couldn’t find any books on the subject as well. There are books for Delphi but I don’t know how useful they really are.
If you are hiring you will have a hard time finding developers as the ecosystem seems to be dead and everybody moved to either C++ or Java. Maybe you could find a Delphi enthusiast who would still be willing to sling some Pascal like in the good old days.
The development environment is great, as you can use whatever you are using for developing web applications. That means a hot reload of your UI and dev console work in the same way as in your browser.
I am not aware of any popular modern RAD tool for generating your html layout (maybe Dreamweaver if that is still your thing). With the modern web technologies that is not even needed as UI is often instantly updated every time you save the file.
The RAM consumption is terrible and the final packages are quite large due to shipping all the things that you don’t need (the entire web browser). The GUI components are obviously not looking native and they could be styled with CSS in the same way as you style a regular website.
I can’t quite figure it out, why do people prefer writing Electron apps as opposed of having a thin backend layer that communicates with the frontend in the user’s existing browser via websockets or long polling or whatever. All you need to do is create a small native wrapper that opens a new tab in the user’s existing browser and package it in an platform specific installer. If you use the Go programming language, writing such a cross platform backend is an easy-peasy task and you can even cross compile your app with minimal hassle. Apparently its more convenient to ship a full blown browser instead.
Despite all the flaws that the Electron has I am writing this text in VSCode which is based on Electron. I doubt it would be as feature packed if they picked one of the other native cross platform frameworks. It’s without doubt much laggier than what its native counterpart would be.
Great development environment. If you are using something like React your UI is automatically updating on every file save. Nothing from the desktop GUI world even comes close to the browser’s dev tools.
Easy to find and hire new developers. Web developers are dime a dozen.
Huge resource waster. You are shipping an entire web browser with all its garbage just to display your GUI. The size of the installer is proportional to the amount of stuff you ship, i.e: it’s huge.
People will say “But there’s WxWidgets, but there’s GTK, but there’s Qt” as if someone is looking for ice cream and everyone is going “But there’s frozen shoe leather, but there’s frozen peas, but there’s an empty refrigerator”
Unfortunately writing a cross platform application that would more or less work the same on all platforms seems like a bad dream. I do wonder if the problem is not in the frameworks itself but actually in the poor programming languages and their awful tooling that we are still using today. If C++ compile times wouldn’t be measured in hours, half of the the problems I have with the existing frameworks would probably go away. Yet here we are.
Keep in mind this overview was only about the programming part of the cross platform GUI. We haven’t even touched the huge list of things that needs to be done in order for your app to feel polished:
Application icon that is sharp on all possible resolutions and visible on both light and dark backgrounds. Oh and btw, your GUI framework does not support .svg icons, so have fun with generating .pngs in all possible resolutions.
Installer for every platform. The users don’t want to fiddle with the environment problems, so you have to make installation as easy as possible (in one click).
Auto updates. Who wants to manually download the entire software from your website every time you write a small patch?
Code signing nonsense. Mac and Windows will display scary looking dialogs if your installer is not signed. Have fun figuring out the needed steps and opening your wallet. The certificates are not cheap and it’s a time consuming process that is not improving your application in any way.
For a performance sensitive applications like games or number crunching scientific tools the desktop apps are still the only way to go. For everything else a development convenience will be chosen. That’s why everything sucks and all your apps are websites now. Weirdly enough the consumers does not seem to care much that their new computer crawls like a snail and a chat program is consuming half of their total memory.
Frankly I don’t really like any of the current GUI frameworks. It’s sad, but what are you going to do? Roll your own and end up with the same half completed framework that already exists out there? Unless you have piles of money to burn, I don’t think it’s an achievable goal for one person or a small team.
If you are still willing to give it a shot, here are some ideas which I would like to see in the next generation cross platform GUI framework:
Fast compile times for debug builds.
Automatic UI reloading so we don’t have to build yet another half finished RAD tool to ease the pain of building the layout.
It should have the same non-native look and feel on all platforms, which could be customized with a CSS or CSS like language (obviously painting the native widgets didn’t work out so far)
It should be event based (for lower power consumption).
It should contain commonly used GUI components such as buttons, text fields, date pickers, tables, layout containers, grids, etc. Check your current operating system’s native toolkit for ideas.
It should compile down to a statically linked blob that you can just execute and run.
Big bonus if you can cross compile your GUI (e.g: creating Windows builds on Linux)
The only non web based GUI framework that comes close to the requirements listed above seems to be Flutter. Unfortunately the desktop platform is not their priority and they will probably need another 10 years in order to be enterprise ready if and only if they will ever deliver .
For the rest of the mere mortals that don’t have the time to dabble in obscure alpha environments and have to ship the damn thing, I would suggest either Qt or JavaFX as they seem the most complete of them all.
 A sharp eye will catch the blasphemy I dared to write down and argue how the bindings exist and you can actually use X programming language to develop in Y framework. Yes the bindings exist but in my limited experience they were quite lacking to the point of uselessness. The documentation was often missing and the tutorials were harder to find if you were even able to find anything. In the end if you have to rely on the documentation of the framework’s primary programming language, you may as well write the entire application in that language instead of fooling around with the half done bindings.
Some will be asking why I didn’t include Swing, Flutter, React native, Sciter, Tcl/Tk or whatever their preferred framework is. I have included the ones that I thought were “mature” and “popular” enough to be deemed usable. They also shouldn’t look like they came straight from the 90’s and should have some kind of documentation. I especially avoided the newer mobile first GUI frameworks as I am specifically focusing on desktop application development.
 You can use QString that comes with a string split functionality.
 Flutter seems promising and it has some great ideas baked in (drawing on canvas, hot UI reloading), but I don’t have high hopes for that project. Google is well known for abandoning their projects as they please and without a giant company behind such a monumental amount of work, this thing will never survive. It also comes with additional baggage (the Dart programming language) which pretty much nobody asked for. Sure it has some neat ideas, but a programming language needs around 10 years to mature and the entire ecosystem such as editor support, debuggers, libraries and so on. I do hope it takes off as the current state of cross platform GUIs is quite terrible and Flutter would be a great wind of change even if it comes with a cost of learning a new language.
[EXTRA] I am well aware of the fact that an engineer can learn any language or framework if they want to. But if you can’t find anyone who would like to work with the chosen technology, the fact that they can learn it doesn’t really help you much.
Here and there you may need an actual expert in the subject, as you may already have a team of people who may not know the technology very well and need some kind of guidance. If the platform is dead, who will be that expert? (Also don’t bring Cobol into this equation. Despite the fact that such people exist, doesn’t mean they are easy to find).