Skip to main content

QML2 to C++ and back again

·3 mins

Update 2014-11-23: I described an improved, but slightly more complicated way to do this in my post QML2 to C++ and back again, with slots and signals.


Here’s a simple example of integrating QML2 and C++, as I couldn’t find an existing one. This is only one way to do it; I think there are a few others, but this seems to be working well enough for me.

I’m going to create an application which contains a text field and a button. You enter some text in the text field, and once you click the button the text will be converted to upper-case. The conversion to upper-case will be done in C++, and the interface drawn in QML2.

First lets write our C++ class, which has a function which takes in a string and returns it as upper-case.

uppercase.cpp

#include "uppercase.h"

Uppercase::Uppercase(QObject *parent) :
    QObject(parent)
{
}

QString Uppercase::uppercase(const QString &in)
{
    qDebug() << "c++: " << in;
    return in.toUpper();
}

The important thing to note here is that we subclass QObject, which gives us access to Qts signals and slots communication model.

Here is the corresponding header file.

uppercase.h

#ifndef UPPERCASE_H
#define UPPERCASE_H

#include <QObject>
#include <QDebug>

class Uppercase : public QObject
{
    Q_OBJECT
public:
    explicit Uppercase(QObject *parent = 0);

signals:

public slots:
    QString uppercase(const QString& in);

};

#endif // UPPERCASE_H

Notice we are exposing the function as a slot, so we can invoke it from QML. I don’t yet fully understand slots in Qt, but the documentation is worth a read.

Now we need to expose this object, and its slot, to our QML application. This is done in main.cpp.

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#include "uppercase.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    Uppercase uppercase;

    engine.rootContext()->setContextProperty("_uppercase", &uppercase);

    return app.exec();
}

The slots on our Uppercase object will be available in QML under the _uppercase identifier.

Finally, we call this function from QML.

main.qml

import QtQuick 2.3
import QtQuick.Window 2.2
import QtQuick.Controls 1.2

Window {
    visible: true
    width: 360
    height: 360

    MouseArea {
        anchors.fill: parent
        onClicked: {
            Qt.quit();
        }
    }

    TextField {
        id: textField1
        x: 31
        y: 169
        placeholderText: qsTr("Enter some text...")
    }

    Button {
        x: 193
        y: 167
        text: qsTr("Uppercase me!")
        onClicked:
            textField1.text = _uppercase.uppercase(textField1.text)
    }
}

And that’s it! I have uploaded the full project to GitHub so you can run it and see it work.

I’m still new to Qt, so this may not be the best way. It looks like you can also use signals, which would probably be better as it means your QML application isn’t tied to your C++ implementation, but I haven’t yet got that working. I described this approach in a later post.