With Qt for Python released, it’s time to look at the powerful capabilities of these two technologies. This article details one solopreneur’s experiences.

The task

Back in 2016, I started developing a cross-platform file manager called fman. Its goal: To let you work with files more efficiently than Explorer on Windows or Finder on Mac. If you know Total Commander and Sublime Text, a combination of the two is what I am going for. Here’s what it looks like:

Picking technologies for a desktop app

The biggest question, in the beginning, was which GUI framework to use. fman’s choice needs to tick the following boxes:

Cross-platform (Windows, Mac, Linux)

Good performance

Support for custom styles

Fast development

At the time, Electron was the most-hyped project. It has a lot of advantages: You can use proven web technologies. It runs on all platforms. Customizing the UI of your application is trivial by means of CSS. Overall, it’s a very powerful technology.

The big problem with Electron is performance. In particular, the startup time was too high for a file manager: On an admittedly old machine from 2010, simply launching Electron took five seconds.

I admit that my personal distaste for JavaScript also made it easier to discount Electron. Before I go off on a rant, let me give you just one detail that I find symptomatic: Do you know how JavaScript sorts numbers? Alphabetically. ’nuff said.

After considering a few technologies, I settled on Qt. It’s cross-platform, has great performance and supports custom styles. What’s more, you can use it from Python. This makes at least me orders of magnitude more productive than the default C++.

Writing a GUI with Python and Qt

Controlling Qt from Python is very easy. You simply install Python and use its package manager to fetch the Qt bindings. Gone are the days where you had to set up gigabytes of software, or even Qt. It literally takes two minutes. I wrote a Python Qt tutorial that shows the exact steps and sample code if you’re interested.

You can choose between two libraries for using Qt from Python:

PyQt is mature but requires you to purchase a license for commercial projects.

Qt for Python is a recent push by Qt the company to officially support Python. It’s offered under the LGPL and can thus often be used for free.

From a code perspective, it makes no difference because the APIs are virtually identical. fman uses PyQt because it is more mature. But given that Qt for Python is now officially supported, I hope to switch to it eventually.

Deploying to multiple platforms

Once you’ve written an application with Python and Qt, you want to bring it into the hands of your users. This turns out to be surprisingly hard.

It starts with packaging. That is, turning your source code into a standalone executable. Special Python libraries exist for solving this task. But they never “just work”. You may have to manually add DLLs that are only required on some Windows versions. Or avoid shipping shared libraries that are incompatible with those already present on the users’ systems. Or add special handling for one of your dependencies. Etc.

Then come installers. On Windows, most users expect a file such as AppSetup.exe. On Mac, it’s usually App.dmg. Whereas on Linux, the most common file formats are .deb, .rpm and .pkg.tar.xz. Each of these technologies takes days to learn and set up. In total, I have spent weeks just creating fman installers for the various platforms.

Code signing

By default, operating systems show a warning when a user downloads and runs your app:

To prevent this, you need to code sign your application. This creates an electronic signature that lets the OS verify that the app really comes from you and has not been tampered with. Code signing requires a certificate, which acts like a private encryption key.

Obtaining a certificate differs across platforms. It’s easiest on Linux, where everyone can generate their own (GPG) key. On Mac, you purchase a Developer Certificate from Apple. Windows is the most bureaucratic: Certificate vendors need to verify your identity, your address etc. The cheapest and easiest way I found was to obtain a Comodo certificate through a reseller, then have them certify my business – not me as an individual.

Once you have a certificate, code signing involves a few more subtleties: On Windows and Ubuntu, you want to ensure that SHA256 is used for maximum compatibility. On Linux, unattended builds can be tricky because of the need to inject the passphrase for the GPG key. Overall, however, it’s doable.

Automatic updates

Like many modern applications, fman updates itself automatically. This enables a very rapid development cycle: I can release multiple new versions per day and get immediate feedback. Bugs are fixable in less than an hour. All users receive the fix immediately, so I don’t get support requests for outdated problems.

While automatic updates are a blessing, they have also been very expensive to set up. The tasks we have encountered so far – packaging, installers and code signing – took a month or two. Automatic updates alone required the same investment again.

Automatic updates on Mac were much easier thanks to the Sparkle update framework. The main challenge was to interface with it via Objective-C from Python. Here too I wrote an article that shows you how to do it.

Linux was “cleanest” for automatic updates. This is because modern distributions all have a built-in package manager such as apt or pacman. The steps for enabling automatic updates were typically:

Host a “repository” for the respective package manager. This is just a collection of static files such as .deb installers and metafiles that describe them.

Upload the installer to the repository, regenerating the metafiles.

Create a “repository file”: It imports the repo into the user’s package manager.

Because fman supports four Linux distributions, this still required learning quite a few tools. But once you’ve done it for two package managers, the others are pretty similar.

OS Versions

There aren’t just different operating systems, there are also different versions of each OS. To support them, you must package your application on the earliest version. For instance, if you want your app to run on macOS 10.10+, then you need to build it on 10.10, not 10.14. Virtual machines are very useful for this. I show fman’s setup in a video.

fman’s build system

So how does fman cope with all this complexity? The answer is simple: A Python-based build script. It does everything from creating standalone executables to uploading to an update server. I feel strongly that releasing a desktop app should not take months, so am making it available as open source. Check it out if you are interested!

Conclusion

Python and Qt are great for writing desktop apps: Qt gives you speed, cross-platform support and stylability while Python makes you more productive. On the other hand, deployment is hard: Packaging, code signing, installers, and automatic updates require months of work. A new open source library called fbs aims to bring this down to minutes.

If you liked this post, you may also be interested in a webinar Michael is giving on the above topics. Sign up or watch it here: Americas / EMEA

32 comments

I still don’t get why people use Python when there is QML (cough*JavaScript*cough)?

I think maybe it’s due to the JS side of Qt lacking some things (File IO?) I know it’s frowned upon byt Qt folk that you can write an entire app in QML, but I don’t think that’s their decision to make. Why should you need to know C++/Qt, Python and JavaScript? I would like you (or anyone else) to only need to know one.

Python has much better libraries for doing desktop-related tasks. JavaScript is a web-first language. I know there’s (eg.) Node. But Python’s target has been desktop for 28 years, whereas it’s rather new for JS.

I Wonder how difficult was to make the dark flat design.
From my experience with Qt, I never success to make a nice flat interface without the help of a designer.
So, I aways keep the default gray style which may looks old.

It could also well be that I did something wrong and you can, if you are careful, deploy to 10.11 from 10.13. For me, it was easiest to simply build on 10.10. Then I don’t have to “worry” about backwards-compatibility.

As a Python/Qt promoter I would say that Python is great but we must take care to the GIL issue which is hard to circumvent. And startup time can also be an issue and require tuning, a lot of lazy loading etc.

Just came across this article today via reddit. Thanks for taking the time to document everything about this build. I am a new Python programmer and just finally about to start working on my first standalone program. I am glad to have found your guides, and I will definitely be checking fman out as well!

Hi will you please provide a concrete example demonstrating how Python is more productive than C++? The blog post announcing the new Python support [0] used a silly “star destroyer” vs. “millenium falcon” analogy but provided no example, and your blog post provides no example either. The “Hello Qt Python” blog post [1] does show some Python code, but it looks like roughly the same amount of code as C++ (but you’ve lost: compile time safety, access to the ever growing list of static analysis sanity checks provided by clang-tidy/CppCoreGuidelines, and the ability to #include other C/C++ libs without wasting your time creating bindings. so what have you gained?)

Feel free to link me to some other site explaining how Python is more productive than C++, so you don’t have to repeat the arguments here. I’m curious because if Python really is more productive than C++, then maybe I’ll switch. But as it stands, repeatedly spouting “Python is more productive than C++” is just spreading FUD (Fear, Uncertainty, and Doubt) against C++.

I could now spend much time giving plenty of examples, but it sounds like your mind is pretty much set in stone. Already “Hello World” is 1 line in Python and 5+ in C++. If you’re happy with C++, do stay with it. But if you want to expand your horizon, just write a few little programs in both languages. Eg. parsing a JSON file. You will feel the difference.

Where’s this 1-line “hello world” you speak of? The code on the “Hello Qt Python” is 35 lines, which is about the same as C++. I said I’d be willing to switch if you could show me an example of Pyhon being more productive. Please stop spreading FUD of you can’t/won’t back up your claim.

Also: Python was the first language I ever tried to learn… but imo C++ blows it out of the water in every aspect. Yes a lot of people use Python, but that doesn’t automatically make it good.

“d3fault”, you phase your questions and points like Mr Herrmann owes you something, when he has gone ahead and provided this article to you for free.

Rather than lean on one person to prove to you that Python is more productive than C++, I recommend you do some wider-ranging Google searching, or better, implement a project in it (trying to learn it once a while ago doesn’t count).

It’s a shame however that you don’t have comments on your site because you make several assertions and assumptions that I flat out don’t agree with.

For one thing, if my workflow requires copying, moving or otherwise, I wouldn’t use a GUI app; I’d use the command line.

I also completely disagree that python is a more productive environment than C++. Yes the lack of a compilation cycle is nice but you lose runtime performance, strict typing and linting that catch many silly mistakes at build time. Python also lacks basic features like multiline lambdas, true multithreading (due to the global interpreter lock) and scoping rules that aren’t dependant on white space.

It seems like you’re trying to solve a problem that was already solved years ago.