Scythe Studio website employs cookies to improve your user experience (Read more)

How to integrate C++ and Qml? Registering C++ class as singleton to Qml

Introduction

In our previous post about integrating C++ and Qml we have explained why it is important to integrate C++ and Qml and covered the basics of this mechanism. In this article we will go into more details and discuss a specific real-life example of integrating elements which can be instantiated one-time only (aka. singletons).

Before we start, let us briefly explain what singleton is, for those who hear this term for the first time. Singleton is a software design pattern that restricts creating an object of a class to a single instance only. There are many use-cases for singletons. I.e. an object that holds a program state and can be accessed from different parts of the application. It is a common to utilize this pattern in Qml as well. A controller that holds some dynamic (not-only) properties and supplies utility functions is a great candidate for a singleton pattern class object. However, you should be careful about using this pattern in application that apply multi-threading.

Qt framework provides multiple ways of registering C++ classes in Qml and each of them has their use. Today we will discuss a most recent one using qt_add_qml_module(). It was introduced in Qt 6.2 and is widely recommended for registering new types in QML.

First of all, we need to create our C++ class we want to expose to QML.

 

#include <QObject>
#include <QtQml/qqml.h>

class ImportantClass : public QObject
{
    Q_OBJECT
    QML_SINGLETON
    QML_ELEMENT
    Q_PROPERTY(int importantNumber READ importantNumber WRITE setImportantNumber NOTIFY importantNumberChanged)

public:
    explicit ImportantClass(QObject *parent = nullptr);

    void setImportantNumber(int num) {
        if (num != m_importantNumber) {
            m_importantNumber = num;
            emit importantNumberChanged();
        }
    }

    int importantNumber() const {
        return m_importantNumber;
    }

public slots:
    double convertFahrenheit(int value) const {
        return value * 1.8 + 32;
    }

signals:
    void importantNumberChanged();

private:
    int m_importantNumber = 10;

};

Everything should look familiar to you, if you have read our previous post in the series. The only differences are Q_SINGLETON and Q_ELEMENT macros, they are important to register a singleton type properly. In ImportantClass we define an importantNumber property and a convertFahrenheit(value) function which, as you may guess from the name, converts provided value to Fahrenheit temperature scale.

Next we need to go to our CMakeLists.txt file and use qt_add_qml_module() command to register our class.

 

qt_add_qml_module(appSingletonExample
    URI SingletonExample
    VERSION 1.0
    QML_FILES
        main.qml
    SOURCES
        ImportantClass.h
        ImportantClass.cpp
)

Provide a URI that you would like to use in the QML import statement. Then specify C++ files your class is in. Congratulations, you have successfully registered a singleton in Qml!

Let us create an example to check if everything works correctly. Here is a simple Qml application consisting of two buttons.

 

import QtQuick
import QtQuick.Controls

import SingletonExample

Window {
  width: 640
  height: 480
  visible: true
  title: qsTr("Hello World")

  Button {
    id: importantNumberButton

    anchors.centerIn: parent

    width: 100
    height: 50

    text: ImportantClass.importantNumber

    onClicked: {
      ImportantClass.importantNumber += 1
    }
  }

  Button {
    anchors {
      top: importantNumberButton.bottom
      horizontalCenter: importantNumberButton.horizontalCenter
    }

    width: 100
    height: 50

    text: "Click to convert"

    onClicked: {
      text = ImportantClass.convertFahrenheit(ImportantClass.importantNumber)
    }
  }
}

 
hello world

 

One of them increases the mentioned-above importantNumber value and second calls convertFahrenheit() function on this value. QtCreator may sometimes complain about wrong imports, but this is not true. In addition, IDE will not provide autocomplete for registered types. We hope it will be fixed soon, because it does not save you from making subtle spelling mistakes which do not stop the execution of QML code, but result in having undefined values.

Next we need to import the registered type using import URI (import SingletonExample in our case). Now we may use ImportantClass in this QML file: Clicking on first button increases a value of ImportantNumber by 1:

 

onClicked: {
  ImportantClass.importantNumber += 1
}

and clicking second button sets its text to Fahrenheit value of importantNumber:

 

onClicked: {
  text = ImportantClass.convertFahrenheit(ImportantClass.importantNumber)
}

Note, that you do not have to initialize ImportantClass objects as it is done internally. Attempts to do that will result in error. Remember about Q_SINGLETON macro?

That is actually it. You have learned how to register singletons in QML from C++ using CMake qt_add_qml_module() command. If you want to learn about integrating C++ and QML we suggest reading official Qt documentation as well as our other blog posts in „How to integrate Qml and C++” series.

If you have any questions, do not hesitate to contact us! Our team of professional developers is always ready to help you provide the best possible software-development services.

Scythe-Studio - Qt Developer

Andrey Staikov Qt Developer

Latest posts

4 Best frameworks for cross-platform desktop app development main image

4 Best frameworks for cross-platform desktop app development

Have you ever noticed that most professional software and games are available for all the most popular platforms? This is normal, because when creating an application you want it to be available to as many customers as possible. A wider audience means more interest in your product, but also more potential profits you can get from it. So it is worth releasing your app on several, different platforms, but how to do it?

Scythe-Studio - Qt Developer

Mateusz Fibor Qt Developer

Qt Charts in Qt 6.2 main image

Qt Charts in Qt 6.2

The Qt Charts module provides the possibility to display various types of charts in order to visualize data. It is available in the Qt framework already for a quite long time, but the framework itself constantly evolves and it’s being improved all the time, so there were changes made to this framework as well. The newest, long-term support (LTS) version of the Qt framework is Qt 6.2 and this version includes most of the changes and improvements. Take a look at our blog post to learn more about improvements made to the Qt Charts in Qt 6.2.

Scythe-Studio - Chief Executive Officer

Łukasz Kosiński Chief Executive Officer