Declaration of VAR

and some other stuff

C++ backend for QML

2016-07-18 15:22:03 +0200

2016-07-18 15:22:03 +0200 | Comments

That’s a question I see around a lot. And despite the official documentation page I decided to create my own example.

You can also read a pretty good article, but I’ve made it simpler.

This article is relevant to the current version of Qt which is 5.7 in the moment.

So, you have a QML application and you want to have some backend logic to be written in C++. It’s actually a good idea, so QML and JS would handle some simple UI manipulation, and C++ would maintain some serious backend shit with rocket science calculations and concurrent processing, so it’s independent from QML UI which is frontend in that case.

Actually, if you are familiar with ASP.NET, you can consider this “C++ backend” thing as calling C# server’s method from JS via XMLHttpRequest, so frontend and backend are separated. It’s not exactly like that, but I hope you get the idea.

Anyway, here’s what needs to be done:

  1. Create a C++ class, that will perform the backend logic, and implement a public slot in it;
  2. Add an instance of that class into the QML context or register a type (I’ll show both options);
  3. Wire up some event to this slot.

Say, we have a C++ class Backend which has a slot doSome():

class Backend : public QObject
{
    // ...
    QString doSome();
    // ...
};

Now let’s consider two ways of adding it to QML.

1st option: add an object as a context property

Add the instance of our class to the QML context in main.cpp:

QQmlApplicationEngine engine;
engine.load(QUrl("qrc:/main.qml"));
Backend *backend = new Backend();
engine.rootContext()->setContextProperty("backend", backend);

And then wire it up to onClicked event of some button in main.qml:

Button {
    text: "Do some"
    onClicked: {
        backend.doSome()
    }
}

2nd option: register a new type

Register a type of our class in main.cpp:

QQmlApplicationEngine engine;
// it's important to do this before engine.load
qmlRegisterType<Backend>("io.qt.Backend", 1, 0, "Backend");
engine.load(QUrl(QLatin1String("qrc:/main.qml")));

Then import it in main.qml:

import io.qt.Backend 1.0

Define it:

Backend {
    id: backend
}

And wire it up to onClicked event of some button:

Button {
    text: "Do some"
    onClicked: {
        backend.doSome()
    }
}

So, now when you push the button, C++ method will do some work.

The main difference between these two methods is that the first method register an already existing object, and the second registers a type an object of which is yet to be created. Aside from that difference, I like the second way better.

I’ve put the full source code of the example with both options on GitHub.



[08.03.2018] Update: More sophisticated example

I wrote another article on the subject with a more sophisticated example: TCP client-server applications.