Connect Qt QML and C++

15Dec 2014

Connect Qt QML and C++

In a new Qt project, it is often desirable to mix C++ and QML code. At least in our experience, it is rare that a project is either pure C++ or pure QML. The Qt Documentation has some overview of the available options of mixing the two. This documentation was somewhat lacking in the past, but has vastly improved for the recently introduced version 5.4.

In particular, we look at an example of integrating a C++ object as a context property into QML. See Embedding C++ Objects into QML with Context Properties in the official documentation that discusses this topic.

The sample code from this project is available on Github.

Project Setup

Qt Quick Application Setup

In Qt Creator, chooce a project of type Qt Quick Application. This allows one to use C++ together with QML.

General Concept

There are different ways to send signals from C++ to QML and back. In this article, we show how to do this by embedding a C++ class directly into QML. This has the advantage that no Qt::connect connections need to be set-up manually.

In our example, we have a Receiver class that is implemented in C++. This class defines a signal sendToQml and a slot receiveFromQml. Both have an integer parameter. The signal is sent to QML, and the slot is invoked from QML.

#ifndef RECEIVER_H
#define RECEIVER_H
#include <QObject>
class Receiver : public QObject
{
  Q_OBJECT
  public:
    explicit Receiver(QObject *parent = 0);
  signals:
    void sendToQml(int count);
  public slots:
    void receiveFromQml(int count);
};
#endif // RECEIVER_H

To invoke the C++ slot, a QML program can then simply call the respective function on the embedded object. In order to receive the C++ signal, the QML program can use the Connections class.

import QtQuick 2.2
import QtQuick.Window 2.1

Window {
  Connections {
    target: receiver
    onSendToQml: {
    console.log("Received in QML from C++: " + count)
    }
  }
  MouseArea {
    anchors.fill: parent
    onClicked: {
      receiver.receiveFromQml(42);
    }
  }
}

Embedding the Object

We have seen how to connect C++ and QML, but what is left is the task of actually embedding the C++ object into QML. This is done by setting a context property. In order to do this, one needs to get the rootContext from the QML engine, and set its property.

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "receiver.h"

int main(int argc, char *argv[])
{
  QGuiApplication app(argc, argv);
  QQmlApplicationEngine engine;
  Receiver receiver;
  QQmlContext* ctx = engine.rootContext();
  ctx->setContextProperty("receiver", &receiver);
  engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
  return app.exec();
}

As mentioned in the overview, there is no need to manually connect the C++ receiver objects signals and slots to QML. Setting the context property is enough for embedding.

Naming Conventions

Please note that Qt has a specific naming convention that needs to be respected for the connection to work. In our example, the Receiver class defines a signal that is called sendToQml. The Connections object can then access this signal with the name onSendToQml. The signal name must be lower case. The other end can then connect the signal by prepending the word on and continue with camel case.

Full Example

The complete source code is on Github. Please clone the code and try to run it. Instructions how to run it can be found in the project’s readme.

When everything is setup correctly, the program outputs a message at startup that it received a value from C++, and when you click in the window, another message should appear that a value was sent to C++. Both messages are sent to the debug console.

Qt Signal Slots App Screenshot

Tags: programming