Dear Readers!

In this post I’m sharing my first impressions about Qt, the cross-platform application framework and widget toolkit, which apparently can be deployed on Linux (also embedded), Windows, macOS, iOS, Android, QNX, Integrity, VxWorks and others, in which list we can see purely embedded platforms as well. In order to gain a bit of an overview about the framework, I created a couple of example applications with various widgets to see it in action. Before we go into that however, let’s see the working environment, with a bit of an emphasis on build tools.

I used Qt Creator and as such qmake to provide me a welcome shortcut to creating small applications, so that I didn’t need to do everything manually. Admittedly though, I seriously considered sticking with CMake at first, as I use it for other learning projects as well, and because Qt Creator does provide support for it. After playing around with CMake a bit though, it became clear, that Creator’s support for CMake is not as advanced as it is for qmake (which is not surprising), so as mentioned before, I decided to use the defaults (qmake). Anyway, just to learn how to use CMake with Qt, I created a Qt-style Hello World project with both CMake and qmake to see how they differ from each other. The first example below is a CMakeLists.txt file I wrote myself, and the second one is a HelloWorld.pro generated by Qt Creator, where the latter I supplemented a bit (with c++ standard and build flags) to make the comparison full. This way both of them are equivalent from an end result perspective (these files will produce debug builds, so please keep that in mind):

CMake

cmake_minimum_required (VERSION 3.9 FATAL_ERROR)

project (QtHelloWorld CXX)

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED 14)

set(CMAKE_CXX_FLAGS "-g -Og ${CMAKE_CXX_FLAGS}")

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)

# Note, that this command exists only since CMake 3.12 (current)
# add_definitions(-DQT_DEPRECATED_WARNINGS) was the way to go earlier
add_compile_definitions(QT_DEPRECATED_WARNINGS)

find_package(Qt5 COMPONENTS Core Widgets REQUIRED)

set(SOURCES
    main.cpp
    window.cpp
    myres.qrc)

add_executable(QtHelloWorld ${SOURCES})
target_link_libraries(QtHelloWorld Qt5::Widgets)

qmake

CONFIG += c++14
QMAKE_CXXFLAGS_DEBUG += -g -Og

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = QtHelloWorld
TEMPLATE = app

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += \
        main.cpp \
        window.cpp

HEADERS += \
        window.h

FORMS += \
        window.ui
        
RESOURCES += \
        myres.qrc

An observant reader might immediately notice, that the CMake file does not have a HEADERS and FORMS list at all, and the RESOURCES is merged into SOURCES. This is because CMake simply assumes the existence of headers and ui files (with appropriate naming and #includes) and as such there is no need to mention them. Their existence is assumed, once the CMAKE_AUTOMOC, CMAKE_AUTOUIC and CMAKE_AUTORCC options have been turned ON, that is. As mentioned before though, I stuck with qmake for the most part, but I also did some random checks with the CMake file, and everything compiled well with it, once the COMPONENTS and SOURCES sections have been properly modified of course. For a good read on using CMake with Qt, please refer to the appropriate documentation.

OK, let’s see some very simple Qt applications I created with the above tools and help of some online guides (aka. non of this is original):

nameA simplistic image viewer, that is capable of opening images with the proper dialogue, and has some basic zooming features (The image is a snapshot from a ‘Stargate: Atlantis’ episode)


nameA very simplistic GUI frontend for ffmpeg


nameA couple of modifiable graphics primitives


nameA mini ‘file manager’. It can create and delete folders at the designated path


nameDepending on the option chosen, a window appears with different underlying implementation

The fact that such simple apps could be created with relative ease tells a lot about the quality of the framework, which I found to be quite extensive. So extensive in fact, that it has a surrogate for most of the components of the C++ standard library, like containers, concurrency, datastreams, etc. Above these, it also has its own unique way of conveying information between objects, the signal-slot mechanism, which basically replaces the observer pattern and/or callbacks. This is achieved through some specifically written macros, which then are “expanded by the preprocessor to declare several member functions that are implemented by the moc”, to quote the official documentation, and where “moc” stands for Meta-Object Compiler. A curious reader might have already asked at this point what is that CMAKE_AUTOMOC option in the CMake file above, well that is for turning on Qt’s moc.

Another phenomenon I observed was Qt’s attempt on avoiding the direct use of C++ for GUI related tasks if possible, whether it is achieved with with .ui files, which are literally XML files, or with using a declarative approach with QML2. Obviously, creating GUI with such tools makes life easier, so I understand Qt’s decision on this. What is even more interesting, is that only the direct use of C++ is avoided, but not it’s indirect use. As mentioned in the build tools section, one needs to enable some options in the CMake file (e.g. CMAKE_AUTOUIC), which are nothing but C++ code generation tools. After poking around in the project directories, I found the appropriate generated .cpp files, so these tools (seems to me) are a kind of an abstraction layer, and they are used to abstract an entire language away. Neat.

Right now that is all the things I can think of, so it is time to finish this post. Obviously, I haven’t used Qt in any serious way to be able to have a well founded opinion, but so far I’m impressed, and hopefully, I’ll be able to dive in more deeply into this framework in the future.

Until that time, thanks for reading.