Access C++ function from QML

47,388

Solution 1

For any C++ code to be called from QML, it must reside inside a QObject.

What you need to do is create a QObject descended class with your function, register it to QML, instantiate it in your QML and call the function. Note also that you have to mark your function with Q_INVOKABLE.

Code:

#ifndef EIGEN_FUNCTION_HEADER_H
#define EIGEN_FUNCTION_HEADER_H

#include <QObject>

class MyObject : public QObject{
   Q_OBJECT
public:
    explicit MyObject (QObject* parent = 0) : QObject(parent) {}
    Q_INVOKABLE int reken_tijden_uit(){
    return 1;
    }
};

#endif // EIGEN_FUNCTION_HEADER_H

main.cpp:

#include <QtGui/QApplication>
#include <QtDeclarative>

#include "qmlapplicationviewer.h"
#include "eigen_function_header.h"

Q_DECL_EXPORT int main(int argc, char *argv[])
{
    QScopedPointer<QApplication> app(createApplication(argc, argv));
    qmlRegisterType<MyObject>("com.myself", 1, 0, "MyObject");

    QmlApplicationViewer viewer;
    viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
    viewer.setMainQmlFile(QLatin1String("qml/tw_looptijden_berekenen/main.qml"));
    viewer.showExpanded();

    return app->exec();
}

QML:

import QtQuick 1.1
import com.myself 1.0

Rectangle {

    width: 360
    height: 360
    Text {
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }
    MyObject {
       id: myobject
    }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            console.log(myobject.reken_tijden_uit())
        }
    }
}

Solution 2

As an alternative to qmlRegisterType() in main.cpp, you can also use context properties to make QObject variables available in QML. (In case you don't require to create different instances of your object with later QML).

Q_DECL_EXPORT int main(int argc, char *argv[])
{
    QScopedPointer<QApplication> app(createApplication(argc, argv));

    QmlApplicationViewer viewer;
    viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
    viewer.setMainQmlFile(QLatin1String("qml/tw_looptijden_berekenen/main.qml"));
    viewer.showExpanded();

    // add single instance of your object to the QML context as a property
    // the object will be available in QML with name "myObject"
    MyObject* myObject = new MyObject(); 
    viewer.engine()->rootContext()->setContextProperty("myObject", myObject); 

    return app->exec();
}

In QML, you can then access the object from anywhere in your code with the given name specified in main.cpp. No additional declarations required:

MouseArea {
    anchors.fill: parent
    onClicked: {
        myObject.reken_tijden_uit()
    }
}

You can find more information on QML<->C++ communication possibilities here: https://v-play.net/cross-platform-development/how-to-expose-a-qt-cpp-class-with-signals-and-slots-to-qml

Share:
47,388
Mathlight
Author by

Mathlight

Updated on March 09, 2020

Comments

  • Mathlight
    Mathlight over 4 years

    I'm trying to make a little program with Qt. I have a main.cpp with the following code:

    #include <QtGui/QApplication>
    #include "qmlapplicationviewer.h"
    
    Q_DECL_EXPORT int main(int argc, char *argv[])
    {
        QScopedPointer<QApplication> app(createApplication(argc, argv));
    
        QmlApplicationViewer viewer;
        viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
        viewer.setMainQmlFile(QLatin1String("qml/tw_looptijden_berekenen/main.qml"));
        viewer.showExpanded();
    
        return app->exec();
    }
    
    int reken_tijden_uit(){
        return true;
    }
    

    and I have a .qml file:

    import QtQuick 1.1
    
    Rectangle {
    
    width: 360
    height: 360
    Text {
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }
    MouseArea {
        anchors.fill: parent
        onClicked: {
            Qt.quit();
        }
    }
    }
    

    Now, when I click on the MouseArea, the program quits. What I want is that it calls the function reken_tijden_uit in the main.cpp file.

    I've googled a lot, and searched on this site to. I've found a couple of answers, but I didn't get one working.

    So what code do I put where so I can call the function reken_tijden_uit in C++?

    Thanks in advance.


    The header file looks like this:

    #ifndef EIGEN_FUNCTION_HEADER_H
    #define EIGEN_FUNCTION_HEADER_H
    
    class MyObject : public QObject{
       Q_OBJECT
    public:
        explicit MyObject (QObject* parent = 0) : QObject(parent) {}
        Q_INVOKABLE int reken_tijden_uit(){
        return 1;
        }
    };
    
    #endif // EIGEN_FUNCTION_HEADER_H
    

    main.cpp:

    #include <QtGui/QApplication>
    #include "qmlapplicationviewer.h"
    #include "eigen_function_header.h"
    
    QScopedPointer<QApplication> app(createApplication(argc, argv));
    
    qmlRegisterType<MyObject>("com.myself", 1, 0, "MyObject");
    
    Q_DECL_EXPORT int main(int argc, char *argv[])
    {
        QScopedPointer<QApplication> app(createApplication(argc, argv));
    
        QmlApplicationViewer viewer;
        viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
        viewer.setMainQmlFile(QLatin1String("qml/tw_looptijden_berekenen/main.qml"));
        viewer.showExpanded();
    
        return app->exec();
    }
    

    and the QML file:

    import QtQuick 1.1
    import com.myself 1.0
    
    Rectangle {
        width: 360
        height: 360
        Text {
            text: qsTr("Hello World")
            anchors.centerIn: parent
        }
        MyObject {
            id: myobject
        }
        MouseArea {
            anchors.fill: parent
            onClicked: {
                myobject.reken_tijden_uit()
            }
        }
    }
    

    And the errors are as follow:

    D:\*\main.cpp:6: error: 'argc' was not declared in this scope
    D:\*\main.cpp:6: error: 'argv' was not declared in this scope
    D:\*\main.cpp:8: error: expected constructor, destructor, or type conversion before '<' token
    

    So what did I do wrong?

  • Chris Browet
    Chris Browet over 12 years
    Best, in a separate .cpp/.h added to your project. Do not forget to include the .h in main.cpp before doing the qmlRegisterType
  • Mathlight
    Mathlight over 12 years
    alright, i've got a couple of errors, i will post a new answer so it's clear y what the problem is...
  • Chris Browet
    Chris Browet over 12 years
    1) You have twice "QScopedPointer<QApplication>...". Remove the first one 2) Move "qmlRegisterType<MyObject>..." just after the second "QScopedPointer...", i.e. inside main{} 3) do a "console.log(myobject.reken_tijden_uit())" to check that it works (will appear in console in qt creator)
  • Chris Browet
    Chris Browet over 12 years
    In the QML? I.e. onClicked: { console.debug(myobject.reken_tijden_uit()) }
  • Mathlight
    Mathlight over 12 years
    alrght, i got still errors, and put the console.log on the onClicked in the qml. the errors are as follow: D:*\main.cpp:-1: In function 'int qMain(int, char**)': AND D:*\main.cpp:14: error: 'qmlRegisterType' was not declared in this scope AND D:*\main.cpp:14: error: expected primary-expression before '>' token
  • Mathlight
    Mathlight over 12 years
    and 3 warnings.... 1); D:*\main.cpp:14: warning: left-hand operand of comma has no effect 2); D:*\main.cpp:14: warning: right-hand operand of comma has no effect 3);D:*\main.cpp:14: warning: right-hand operand of comma has no effect
  • Mathlight
    Mathlight over 12 years
    alright, i think it's working now, because i've got now 15 errors (A) the first one is: D:\qt\tw_looptijden_berekenen\tw_looptijden_berekenen-build-‌​desktop-Qt_4_8_0_for‌​_Desktop_-_MinGW__Qt‌​_SDK__Debug\debug\mo‌​c_eigen_function_hea‌​der.cpp:12: error: #error "The header file 'eigen_function_header.h' doesn't include <QObject>."
  • Chris Browet
    Chris Browet over 12 years
    Indeed. Edited for #include <QObject>
  • Mathlight
    Mathlight over 12 years
    yeeey :P srr, i thought i had it but didn't ;P it works now. Thanks for the help ;)
  • johnbakers
    johnbakers over 10 years
    If you instantiate it in QML, then how can you give this instance access to other objects you have in C++? For example, if an invokable function requires pointers to other objects in your C++ environment, you'd have to give the instance some way of accessing them. How?
  • KernelPanic
    KernelPanic almost 9 years
    @hellofunk why is function main declared as Q_DECL_EXPORT?
  • johnbakers
    johnbakers almost 9 years
    @MarkoFrelih see this: stackoverflow.com/questions/13911387/… i can't remember the reasoning in this particular case, but i don't use Qt anymore and this was a couple years ago
  • Vincent Fourmond
    Vincent Fourmond almost 7 years
    Some important caveat: the function marker with Q_INVOKABLE has to be public (or at least, not private, haven't checked for protected).
  • Mikolasan
    Mikolasan about 5 years
    There is a [flowchart in Qt docs] (doc.qt.io/qt-5/…) that helps to decide when better to use qmlRegisterTypes approach and when setContextProperty