从QML访问C++函数

45

我正在尝试使用Qt制作一个小程序。我有一个包含以下代码的main.cpp文件:

#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;
}

我有一个.qml文件:

import QtQuick 1.1

Rectangle {

width: 360
height: 360
Text {
    text: qsTr("Hello World")
    anchors.centerIn: parent
}
MouseArea {
    anchors.fill: parent
    onClicked: {
        Qt.quit();
    }
}
}
现在,当我点击MouseArea时,程序会退出。我希望它调用main.cpp文件中的函数reken_tijden_uit
我已经搜索了很多,也在这个网站上搜索过。我找到了一些答案,但没有一个可以正常工作。
所以我应该把什么代码放在哪里,这样我就可以在C++中调用reken_tijden_uit函数?
提前致谢。
头文件看起来像这样:
#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();
}

和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: {
            myobject.reken_tijden_uit()
        }
    }
}

错误信息如下:

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

那么,我做错了什么吗?


请查看以下帖子,这可能对你有所帮助。https://dev59.com/nm025IYBdhLWcg3w76lq - shofee
嗨,我已经检查过了,但它并不完全是我想要的... 我想在鼠标区域中添加一个onclick事件来调用cpp函数。(在JavaScript中只需使用reken_tijden_uit();,那么在C++和QML中如何实现呢? - Mathlight
2个回答

65
任何要从QML中调用的C++代码都必须位于一个内。
你需要做的是创建一个继承自的类,包含你的函数,将其注册到QML中,在你的QML文件中实例化它并调用该函数。 同时还需注意,你必须使用来标记该函数。
代码:
#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())
        }
    }
}

  1. 你有两个 "QScopedPointer<QApplication>..."。删除第一个。
  2. 将 "qmlRegisterType<MyObject>..." 移动到第二个 "QScopedPointer..." 后面,即在 main{} 中。
  3. 执行 "console.log(myobject.reken_tijden_uit())" 来检查它是否正常工作(将出现在 qt creator 的控制台中)。
- Chris Browet
如果您在QML中实例化它,那么如何让此实例访问您在C++中拥有的其他对象?例如,如果可调用函数需要指向C++环境中其他对象的指针,则必须提供某种方式让该实例访问它们。怎么做呢? - johnbakers
@hellofunk 为什么将函数 main 声明为 Q_DECL_EXPORT - KernelPanic
@MarkoFrelih 看一下这个:https://dev59.com/L2Yr5IYBdhLWcg3wKHEp 我不记得这个特定情况的理由了,但我不再使用 Qt,并且这是几年前的事了。 - johnbakers
一些重要的注意事项:带有 Q_INVOKABLE 的函数标记必须是 public(或者至少不是 private,我还没有检查 protected)。 - Vincent Fourmond
显示剩余8条评论

15

在 main.cpp 中,作为 qmlRegisterType() 的替代方案,您还可以使用上下文属性来使 QObject 变量在 QML 中可用。(假设您不需要在稍后的 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();
}

在QML中,您可以使用主文件(main.cpp)中指定的名称来访问对象,无需进行其他声明:

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

您可以在此处找到有关QML<->C++通信可能性的更多信息:https://v-play.net/cross-platform-development/how-to-expose-a-qt-cpp-class-with-signals-and-slots-to-qml


1
在Qt文档中有一个流程图,可以帮助决定何时更好地使用_qmlRegisterTypes_方法,以及何时使用_setContextProperty_方法。 - Mikolasan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接