Setting up and getting started

Getting ready to create our first Kirigami application

Installing required packages

Before getting started, we must install a few things. We need a C++ compiler, Qt development packages, and Kirigami.

On Ubuntu, Debian and Neon we can install these with APT:

sudo apt install build-essential extra-cmake-modules cmake qtbase5-dev qtdeclarative5-dev libqt5svg5-dev qtquickcontrols2-5-dev qml-module-org-kde-kirigami2 kirigami2-dev libkf5i18n-dev gettext

On Arch-based distributions (like Manjaro) we can use Pacman:

sudo pacman -Syu base-devel extra-cmake-modules cmake kirigami2 kde-sdk-meta gettext

For Fedora, we use DNF:

sudo dnf groupinstall "Development Tools" "Development Libraries"
sudo dnf install extra-cmake-modules cmake qt5-qtbase-devel qt5-qtdeclarative-devel qt5-qtquickcontrols2-devel kf5-kirigami2 kf5-kirigami2-devel gettext

Further information for other distributions can be found here.

Getting ready

While there are tools that can easily set up our files, we are going to create them manually. This will let us better understand the pieces that are going to make up our new application.

First we create our project folder. We are going to call ours ‘helloworld’.

helloworld
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    ├── contents
    │   └── ui
    │       └── main.qml
    ├── main.cpp
    └── resources.qrc

Within this folder we are going to create a src folder and CMakeLists.txt. It is generally considered good practice to place all our main code files in a src folder. Our src folder in turn will contain a folder named contents, which itself contains a folder called ui. Here is where we will create our QML files.

This is KDE convention, but not all KDE projects use this structure. You are free to set things up differently, but you will have to take this into account when creating your CMakeLists.txt and resources.qrc files.

CMakeLists.txt

CMakeLists.txt files are needed to use KDE’s build system of choice, CMake. The CMakeLists.txt file in our top-level folder is going to specify some of our application’s characteristics. It also includes some of the dependencies we need to compile it.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cmake_minimum_required(VERSION 3.16)
project(helloworld)

set(KF_MIN_VERSION "5.68.0")
set(QT_MIN_VERSION "5.12.0")

find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)

set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})

include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)

find_package(Qt5 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS Core Quick Test Gui QuickControls2 Widgets)
find_package(KF5 ${KF_MIN_VERSION} REQUIRED COMPONENTS Kirigami2 I18n CoreAddons)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_subdirectory(src)

feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)

The CMakeLists.txt defines how to build your projects. Most of the content here is just to bootstrap your project. You can read a line-by-line, in-depth explanation of what this CMakeLists file does here.

The most important thing to keep in mind is that the Qt and KDE Frameworks dependencies are managed with find_package. You will have to modify these lines and include any additional components that you decide to use during the development of your application.

The final line, add_subdirectory(src), points CMake into the ‘src’ directory, where our source code is located. Let’s delve into the CMakeLists.txt file in there.

1
2
add_executable(helloworld main.cpp resources.qrc)
target_link_libraries(helloworld Qt5::Quick Qt5::Qml Qt5::Gui Qt5::QuickControls2 Qt5::Widgets KF5::Kirigami2 KF5::I18n)

This one’s a lot shorter! Let’s go through what it does:

  • add_executable creates an executable from the given source files.
  • target_link_libraries links the libraries used in our code to our executable.

Now that CMake has been taken care of, let’s look at the files we are going to spend the majority of our time working with.

resources.qrc

resources.qrc contains the list of all QML files as well as other files (like custom icons) that will be included in the binary.

1
2
3
4
5
<RCC>
    <qresource prefix="/">
        <file alias="main.qml">contents/ui/main.qml</file>
    </qresource>
</RCC>

Notice the line <file alias="main.qml">contents/ui/main.qml</file>. It details which QML files are going to be included in the compilation process. In our case we are only using main.qml, but if we were to add more QML files to our code, we’d need to make sure we include it in resources.qrc file by adding another line like this one.

You can read more about the specifics of how the Qt resource system works in Qt’s docs.

main.cpp

main.cpp handles the ‘business logic’ of our application. C++ is handy because it is flexible and fast, even if it is more involved than other programming languages.

main.cpp is also the entrypoint to our application. The two parts of our project, the backend and the user interface, are both set up and started here.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QtQml>
#include <QUrl>
#include <KLocalizedContext>
#include <KLocalizedString>

int main(int argc, char *argv[])
{
    QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);
    KLocalizedString::setApplicationDomain("helloworld");
    QCoreApplication::setOrganizationName("KDE");
    QCoreApplication::setOrganizationDomain("kde.org");
    QCoreApplication::setApplicationName("Hello World");

    QQmlApplicationEngine engine;

    engine.rootContext()->setContextObject(new KLocalizedContext(&engine));
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    if (engine.rootObjects().isEmpty()) {
        return -1;
    }

    return app.exec();
}

For now, we don’t need to go into too much detail regarding what our main.cpp code does, but its role will grow significantly more important once we decide to add more complex functionality to our application in the future. If you want to get ahead, you can read more about how this main.cpp works in this page.

main.qml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Includes relevant modules used by the QML
import QtQuick 2.6
import QtQuick.Controls 2.0 as Controls
import QtQuick.Layouts 1.2
import org.kde.kirigami 2.13 as Kirigami

// Base element, provides basic features needed for all kirigami applications
Kirigami.ApplicationWindow {
    // ID provides unique identifier to reference this element
    id: root

    // Window title
    // i18nc is useful for adding context for translators, also lets strings be changed for different languages
    title: i18nc("@title:window", "Hello World")

    // Initial page to be loaded on app load
    pageStack.initialPage: Kirigami.Page {

        Controls.Label {
            // Center label horizontally and vertically within parent element
            anchors.centerIn: parent
            text: i18n("Hello World!")
        }
    }
}

We finally reach our QML file, where we will be handling our application’s frontend.

If you know some Javascript, then much of QML will seem familiar to you (though it does have its own peculiarities). Qt’s documentation has an extensive amount of material on this language if you feel like trying something on your own. Over the course of these tutorials we will be focusing much of our attention on our QML code, where we can use Kirigami to get the most out of it.

For now, let’s focus on main.qml. First we import a number of important modules:

  • QtQuick, the standard library used in QML applications.
  • QtQuick Controls, which provides a number of standard controls we can use to make our applications interactive.
  • QtQuick Layouts, which provides tools for placing components within the applications window.
  • Kirigami, which provides a number of components suited for creating applications that work across devices of different shapes and sizes.

We then come to our base element, Kirigami.ApplicationWindow which provides some basic features needed for all Kirigami applications. This is the window that will contain each of our pages, the main sections of our UI.

We then set the id property of Kirigami.ApplicationWindow to ‘root’. IDs are useful because they let us uniquely reference a component, even if we have several of the same type.

We also set the window title property to ‘Hello World’. You’ll notice that we have wrapped our “Hello World” string in a function called i18nc, where we detail the context of the string as well as the string itself.

We then set the first page of our page stack. Most Kirigami applications are organised as a stack of pages, each page containing related components suited to a specific task. For now, we are keeping it simple, and sticking to a single page. With pageStack.initialPage: Kirigami.Page{...} we set the first page presented upon loading the application to a Kirigami.Page, which will contain all our content.

Finally, we include in our page a Controls.Label that lets us place text on our page. We use anchors.centerIn: parent to center our label horizontally and vertically within our parent element. In this case, Controls.Label’s parent component is Kirigami.Page. The last thing we need to do is set the text: text: i18n("Hello World!").

Compiling and running the application

We are almost at the finish line. The last thing we need to do is build and compile our application. To do that, we need to enter our ‘helloworld’ folder in our terminal application of choice and run the following command:

cmake -B build/ . && cmake --build build/

Voila! The resulting binary can be found in helloworld/build/src/<project name>. Run it, and you will see your very first Kirigami app appear before your very own eyes.

Screenshot of the generated Kirigami application