Search code examples
qtqmlqtquick2qt5.5qtquickcontrols

What is the most formal way to invoke C++ code in response to a QML button?


Using qt 5.5, qt quick controls 1.4 and the below qt creator boilerplate code: what is the most FORMAL way to invoke C++ code in response to a button (just debug text to screen)?

// main cpp
#include <QApplication>
#include <QQmlApplicationEngine>

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

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

     return app.exec();
}

and the QML file inside the qml.qrc:

import QtQuick 2.5
import QtQuick.Controls 1.4

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


    Button {
        id: add
        x: 248
        y: 222
        text: qsTr("add")
    }
}

I am aware of this as a possible answer but it looks a very complicated way to just hook a button to a code! If this is The Formal way to use Qt 5.5 and QML then this should be the answer.


Solution

  • As you can see in the documentation, you have many options:

    • The class can be registered as an instantiable QML type. This was the option proposed by @BaCaRoZzo
    • The class can be registered as a Singleton Type
    • An instance of the class can be embedded into QML code as a context property or context object
    • The Qt QML module also provides ways to do the reverse and manipulate QML objects from C++ code. This was the option proposed by @hyde

    In your case, I'd prefer the last option because it requires fewer lines of code.

    Example:

    main.cpp

    // main cpp
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include "myclass.h"
    
    int main(int argc, char *argv[])
    {
         QGuiApplication app(argc, argv);
    
         QQmlApplicationEngine engine;
         engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
         QObject *item = engine.rootObjects().first();
    
         MyClass myClass;
         QObject::connect(item, SIGNAL(qmlSignal(QString)),
                          &myClass, SLOT(cppSlot(QString)));
    
         return app.exec();
    }
    

    main.qml

    import QtQuick 2.5
    import QtQuick.Controls 1.4
    
    ApplicationWindow {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
    
        signal qmlSignal(string msg)
    
        Button {
            id: add
            x: 248
            y: 222
            text: qsTr("add")
            onClicked: qmlSignal(text)
        }
    }
    

    myclass.h

    #ifndef MYCLASS_H
    #define MYCLASS_H
    
    #include <QObject>
    #include <QDebug>
    
    class MyClass : public QObject
    {
        Q_OBJECT
    public slots:
        void cppSlot(const QString &msg) {
            qDebug() << "Called the C++ slot with message:" << msg;
        }
    };
    
    #endif // MYCLASS_H