2

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.

Community
  • 1
  • 1
Raiden Core
  • 1,535
  • 12
  • 13
  • 2
    Either by registering context properties or by defining new QML types, as depicted [here](http://doc.qt.io/qt-5/qtqml-cppintegration-definetypes.html). – BaCaRoZzo Jan 25 '16 at 22:59
  • 3
    When thinking about "complicated", note that QML is loaded at runtime. C++ on the other hand doesn't exist at runtime any more, it has been compiled into machine code. The complication, if you want to call it so, arises from this. Anyway, just emit signal from QML, connect to a Qt slot in C++, in your own QObject subclass. – hyde Jan 26 '16 at 05:26
  • 3
    Looking at the linked question, it creates an unnecessary dependency between different parts of the program, emitting signal is definitely a more Qt'ish way of doing it. – hyde Jan 26 '16 at 05:35
  • How does this Qt`sh way work ? Please propose an answer with code if you have time. – Raiden Core Jan 26 '16 at 07:21
  • @BaCaRoZzo which one should be the best under which circumstances and why: please propose an answer with code if you can. – Raiden Core Jan 26 '16 at 07:59
  • 2
    Usually your C++ code shouldn’t know about buttons, which would be too tight coupling between C++ and QML, but there might be slots exposed to QML to trigger actual functionality. so onClicked would call a slot/Q_INVOKABLE to starts the actual operation, or (even better) update a property. – Frank Osterfeld Jan 26 '16 at 18:57

2 Answers2

3

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
Tarod
  • 6,732
  • 5
  • 44
  • 50
  • Thanks, it worked. Based on what @BaCaRoZzo said. Now I have two options, Is there a third option ? – Raiden Core Jan 26 '16 at 11:37
  • @RaidenCore it's a third I didn't mention (mostly because I'm used to the others). Simply my fault. :) You can find further information [here on](http://doc.qt.io/qt-5/qtqml-cppintegration-interactqmlfromcpp.html#invoking-qml-methods). – BaCaRoZzo Jan 26 '16 at 12:56
2

I made an example to show both approaches mentioned by @BaCaRoZzo :

// main.cpp

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "myclass.h"

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

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


    MyClass myclass;

    engine.rootContext()->setContextProperty("_myclass", &myclass);

    QObject *item = engine.rootObjects().first();

    QObject::connect(item, SIGNAL(qmlSignal(QString)), &myclass, SLOT(cppSlot(QString)));

    return app.exec();
}

The header file of the c++ class that is invoked from qml:

// myclass.h
#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>

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

signals:


public slots:
    void count();
    void cppSlot(const QString &msg);
};

#endif // MYCLASS_H

and its implementation:

#ifndef MY_CLASS_H
#define MY_CLASS_H


// myclass.cpp
#include "myclass.h"
#include <QDebug>

MyClass::MyClass(QObject *parent) : QObject(parent)
{

}

void MyClass::count()
{
    static int i = 0;
    i++;
    qDebug() << "wow =" + QString::number(i) ;
}

void MyClass::cppSlot(const QString &msg)
{
    qDebug() << "Called the C++ slot with message:" << msg;
}

#endif

The user interface qml file with two buttons that show both approaches:

//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: button
        x: 218
        y: 229
        width: 148
        height: 31
        text: qsTr("run cpp method ctxt prop")
        onClicked: _myclass.count()
    }

    Button {
        id: button1
        x: 218
        y: 300
        width: 148
        height: 23
        text: qsTr("run cpp method qmlsignal")
        onClicked: qmlSignal(text)
    }

}
Raiden Core
  • 1,535
  • 12
  • 13
  • Great! :) Happy coding! – Tarod Jan 28 '16 at 11:32
  • Hmmmmm.....Qt is new to me, I am a WPF developer. I wonder: is there a data binding technique in qt similar to WPF, one way, two way data binding. I might post a question about this after doing my tonight Qt homework. – Raiden Core Jan 28 '16 at 18:11
  • 1
    Well, with Qt you can achieve that using singal/slot mechanism. For example, if we want to do something similar to [this](http://www.c-sharpcorner.com/blogs/wpf-binding-one-way-and-two-way1), the idea would be connect text fields to tables on the one hand, and row modifications/selections to the required text fields on the other hand. – Tarod Jan 29 '16 at 06:56