Qt is a popular cross-platform application framework developed by the Qt Company and distributed via both proprietary and open source licenses. Qt is designed for creating applications that can run on different platforms without the need to change codebase for each platform. Itโs most often used for creating multi-platform applications and graphical user interfaces (GUIs).
This tutorial will show you how to create a simple Qt application with the Qt Quick graphical user interface. Weโll use CMake as our project format and C++ as the language for our source code. Our example application is simple in design and consists of just one window.
Contents
Qt Quick is a user interface library for creating declarative user interfaces that are separated from programming logic. This framework is implemented as part of the Qt library set. QML is a user interface specification and programming language.
CMake is the project generator for many platforms and build systems. The CMake build system uses the unified file format and is able to generate makefiles, Visual Studio solutions, and projects for many other build systems from the same project file. You can check out some CMake examples on the official website if you want to learn more.
Prerequisites
In order to develop an application using CMake with Qt QML, we first need to make sure that we have all the necessary tools.
Compiling and running our sample project requires GCC, CMake, GNU Make, and the Qt development libraries with Qt Quick enabled. This tutorial specifies how to install pre-compiled packages from standard repositories.
Environment Setup
Debian-based Systems
The following instructions apply to:
- Ubuntu 16.04
- Debian 9
sudo apt-get install -y \
build-essential \
cmake \
qtbase5-dev \
qtdeclarative5-dev \
qtquickcontrols2-5-dev \
qml-module-qtquick2 \
qml-module-qtquick-controls
RedHat-based Systems
The following instructions apply to:
- Fedora 22 and higher
sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y \
cmake \
gcc-g++ \
qt5-qtbase-devel \
qt5-qtdeclarative-devel \
qt5-qtquickcontrols \
qt5-qtquickcontrols2-devel
- CentOS 7
sudo yum groupinstall -y "Development Tools"
sudo yum install -y \
cmake \
qt5-qtbase-devel \
qt5-qtdeclarative-devel \
qt5-qtquickcontrols \
qt5-qtquickcontrols2-devel
Ensure the success of your cross-platform application
Get yourself an expert dedicated team that will choose the most suitable tools, technologies, and development approaches for your project.
Directory Structure
The directory of the project is laid out as follows:
$ tree
.
โโโ CMakeLists.txt
โโโ src
โโโ CMakeLists.txt
โโโ main.cpp
โโโ main.qml
โโโ qml.qrc
1 directory, 5 files
All source files for the project go in src
, and the main project specifications in CMake format go in CMakeLists.txt
. Larger projects tend to be organized in sub-directories for modules, executables, and libraries, each with its individual sub-directory and CMakeLists.txt
file.
Main Window GUI File
With this example, we start with the declarative file for the user interface, which is specified in src/main.qml
. The code below creates a small window without any controls:
src/main.qml
import QtQuick 2.0
import QtQuick.Controls 1.0
ApplicationWindow
{
visible: true
width: 640
height: 480
title: qsTr("Minimal Qml")
}
The next code imports all necessary modules. The exact version of QtQuick
is not the same as the version of the Qt framework used. The QtQuick.Controls
library contains some basic controls for the user interface.
import QtQuick 2.0
import QtQuick.Controls 1.0
The main application window is represented with the ApplicationWindow
control in the Qt Quick library:
ApplicationWindow
{
...
}
There are four attributes of the main window that specify its size and title. The visible
attribute specifies that the window should be shown right after launch.
visible: true
width: 640
height: 480
title: qsTr("Minimal Qml")
Related project
Cross-Platform Data Backup Solution Development: Windows, Android, macOS, iOS
Discover the story of the client, partnering with Apriorit for over 18 years: weโve started with a simple Windows development project and now help them support a complex cross-platform data management solution.
QML Resource File
Next, letโs look at the QML resource file for an application that consists of a sole QML file named main.qml
. The file is written in XML with the RCC
element as root and qresource
as the element for resources of all groups. This project contains only one group thatโs root (i.e. "/"
). Larger projects may contain additional qresource
elements for each resource subgroup (e.g. customControls
, customWindows
, etc.).
src/qml.qrc
<RCC>
<qresource prefix="โ">
<file>main.qml<โfile>
<โqresource>
<โRCC>
Application Code
The main entry point of the application provides the C++ code for displaying the Qt Quick user interface.
src/main.cpp
#include <QApplication>
#include <QQmlApplicationEngine>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:โmain.qml")));
return app.exec();
}
The following code constructs a standard object for a Qt application:
QApplication app(argc, argv);
In the next section, the QML parsing object is initiated for the application. This object receives a string with the address of the main QML resource as the construction parameter. In this case, qrc:/main.qml
is the address specified in the qml.qrc
file. qrc
is the default prefix for the QML resource, and /main.qml
references the resource named main.qml
in the root resource directory ("/"
).
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:โmain.qml
The exec
method starts the Qt application:
return app.exec();
Read also
Building Cross-Platform Apps With React Native: How to Run an App on Multiple Platforms from a Single Codebase
Explore a practical overview of top cross-platform development technologies and frameworks, along with a step-by-step React Native development guide with code examples from Apriorit experts.
Project Files
Now weโll show you how to deploy a Qt Quick application using the CMake project format.
Letโs look at the main project file. The first line sets the minimum version of CMake for the project. It then includes the Qt5 framework in the application as well as the src
subdirectory so that CMake will search for the project file (CMakeLists.txt
) there.
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
# 3rd party tools
find_package(Qt5 COMPONENTS Widgets Qml Quick REQUIRED)
# Directory with source code
add_subdirectory(src)
This is the project file for the executable:
src/CMakeLists.txt
include_directories(${Qt5Widgets_INCLUDE_DIRS} ${QtQml_INCLUDE_DIRS})
add_definitions(${Qt5Widgets_DEFINITIONS} ${QtQml_DEFINITIONS} ${${Qt5Quick_DEFINITIONS}})
qt5_add_resources(QT_RESOURCES qml.qrc)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(PROJECT "MinimalQml")
project(${PROJECT})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -std=c++11 -fstrict-aliasing -pedantic-errors -pedantic -Wno-deprecated-declarations -Wno-unused-variable")
if(NOT DEFINED HEADERS)
file(GLOB HEADERS ${CMAKE_CURRENT_SOURCE_DIR}โ*.h)
endif()
if(NOT DEFINED SOURCES)
file(GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}โ*.cpp)
endif()
source_group("Header Files" FILES ${HEADERS})
source_group("Source Files" FILES ${SOURCES})
add_executable(${PROJECT} ${HEADERS} ${SOURCES} ${QT_RESOURCES})
target_link_libraries(${PROJECT}
Qt5::Widgets
Qt5::Qml
Qt5::Quick
)
The header files for the Qt project should be included so that the makefiles generated will specify them in the corresponding compilation commands. There Qt5Widgets stands the header files for the Qt Framework and Qt QML invokes special files for QML functions.
include_directories(${Qt5Widgets_INCLUDE_DIRS} ${QtQml_INCLUDE_DIRS})
The definitions as well as the Qt include files should be specified in the makefile compilation commands.
add_definitions(${Qt5Widgets_DEFINITIONS} ${QtQml_DEFINITIONS} ${${Qt5Quick_DEFINITIONS}})
The Qt framework requires code to be created from the Qt resource files. This is achieved using the special qt5_add_resources
command. The QML resource file path relative to this file is passed as an argument:
qt5_add_resources(QT_RESOURCES qml.qrc)
For Qt projects with a graphical user interface, the compiler needs special parameters in order to compile:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
Qt programs require several additional compilation steps for moc, rcc,
and uic
:
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
The name of the project, which will be used as the name of the compiled executable, is specified using the set
command, which receives the name of a variable (i.e. PROJECT
) and its value.
set(PROJECT "MinimalQml")
The project
command sets the current project within the CMake file and receives the value of the variable defined above:
project(${PROJECT})
The compiler flags for compiling C++ sources are set below. These flags set very strict compilation rules and help to detect and locate a lot of potential issues during compilation:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -std=c++11 -fstrict-aliasing -pedantic-errors -pedantic -Wno-deprecated-declarations -Wno-unused-variable")
There are also conditional commands in CMake. The code below detects if there are HEADERS
in the project. If header files were not previously set, the file(GLOB ... *.h)
command creates a list of all header files in the current directory and passes them as header files of the current project. The same applies to the *.cpp
sources that are stored in the SOURCES
variable if that was not defined.
if(NOT DEFINED HEADERS)
file(GLOB HEADERS ${CMAKE_CURRENT_SOURCE_DIR}โ*.h)
endif()
if(NOT DEFINED SOURCES)
file(GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}โ*.cpp)
endif()
The source_group
definition creates a group of files that are placed in some build systems (e.g. project sub-directories in Visual Studio).
source_group("Header Files" FILES ${HEADERS})
source_group("Source Files" FILES ${SOURCES})
This command states that the project results in an executable file. The first parameter receives the name of an executable file (which in this case is the same as the name of the project). The rest of the arguments are project sources, headers, and compiled Qt resources.
add_executable(${PROJECT} ${HEADERS} ${SOURCES} ${QT_RESOURCES})
The set of libraries that will be linked with the executable above is set with the target_link_libraries
command. Like the command above, it receives the name of a projectโs executable and a list of libraries. In this case, the project uses only Qt framework libraries.
target_link_libraries(${PROJECT}
Qt5::Widgets
Qt5::Qml
Qt5::Quick
)
Read also
Comprehensive Guide to End-to-End Cross-Platform Testing of React Native Apps
Streamline cross-platform testing with end-to-end approach. Ensure flawless user experience while saving QA resources and automating routine activities.
Building the Project
Now itโs time for building with CMake.
You can build your program using the commands below. CMake takes a directory with the main projectโs CMakeLists.txt
file as an argument. Then it creates build files for GNU make
, which builds an executable.
cd <PathToProject>
mkdir build && cd build
cmake ..
make
After a successful build, the binary MinimalQml
will end up in build/src/.
.โsrcโMinimalQml
Working on a Project with Qt Creator
You can probably avoid working with Qt Creator by creating a Qt QML C++ plugin with CMake, but we prefer going the traditional route.
If you want to know more about Qt Creator, you can find the official manual here. Now, letโs look into how we can use Qt Creator with our Qt CMake example project.
Go to the Welcome tab in the main window and select Open Project (2).
In the dialog box that opens, locate the CMakeLists.txt file in the projectโs root directory.
Next, select the version of Qt framework that youโll use to compile the project. If you have multiple frameworks installed, itโs possible to select several.
After opening the project, its directory structure will be visible in the Projects panel in Qt Creator.
The C++ source files are treated as usual by the editor.
QRC resource files are opened as a resource tree.
From the resource tree, you can open QML files for the project.
Conclusion
We hope that this short tutorial has been useful and that you were able to take away some practical tips on using CMake with Qt. If you wish to learn more about Qt development, check out our article on Organizing RPC via QT. And if you ever need a team of competent C++ developers with years of experience, just send us your request for proposal. Weโd be happy to talk.
Links
The source code for this project is available at our GitHub:
Qt Documentation:
CMake:
Letโs build your cross-platform app together!
Describe your application idea and requirements and weโll get back to you with development ideas, strategies, and approaches.