【问题标题】:QML timer not triggeredQML 计时器未触发
【发布时间】:2018-06-20 04:17:01
【问题描述】:

我在 qml 中有一个计时器(在 StackView 中查看),我尝试从 C++ 代码开始,调用 javascript 函数。但我的计时器永远不会被触发。我究竟做错了什么?我的流程是 a.qml -> b.qml(点击按钮)

文件 b.qml:

Item {
    function connectionConfirmed() {
        myTimer.start()
        console.log("started timer")
    }
    Timer {
        interval: 1000; running: false; repeat: false
        id: myTimer
        onTriggered: {
            console.log("timer triggered")
        }
    }
}

文件 main.qml:

ApplicationWindow {
    id: root
    visible: true
    width: 320
    height: 530

    StackView {
        id: stackView
        initialItem: "qrc:/a.qml"
        anchors.fill: parent
    }
}

文件a.qml

MouseArea{
    anchors.fill: parent
    onClicked: {
        stackView.push("qrc:/b.qml")
    }
}

C++部分:

connect(&myObjectInstance, &X::somethingHappend, this, [this](){
        QQmlComponent component(&engine_, "qrc:/b.qml");
        QObject *obj = component.create();
        QVariant returnedValue;
        QMetaObject::invokeMethod(obj, "connectionConfirmed",
            Q_RETURN_ARG(QVariant, returnedValue));
        delete obj;
    });

输出是: started timer

当我尝试设置running: true定时器被触发时,是否意味着我无法从JS函数启动定时器?

【问题讨论】:

  • 我通过使用 Button 调用 connectionConfirmed 函数测试了您的代码,它工作正常,我认为错误在您的代码的另一部分,请花点时间提供一个像样的minimal reproducible example跨度>

标签: c++ qt qml


【解决方案1】:

问题是因为您假设在 C++ 端创建的组件与在 QML 端创建的组件相同。 .qml 文件是源代码,当你调用它时,它们每次都会生成一个不同的对象。


行为说明:

connect(&myObjectInstance, &X::somethingHappend, this, [this](){
        QQmlComponent component(&engine_, "qrc:/b.qml");
        QObject *obj = component.create();
        QVariant returnedValue;
        QMetaObject::invokeMethod(obj, "connectionConfirmed",
            Q_RETURN_ARG(QVariant, returnedValue));
        delete obj;
    });

在这段代码中,您首先创建组件,然后创建对象,调用用js编写的函数,该函数刚刚执行并打印消息,然后将其删除,所以当您删除它时,它永远不会开火。 new Timer,由于这个原因,打印第一条消息的似乎是在 QML 中创建的项目,但事实并非如此,新项目打印了它。


调用 C++ QML 函数会带来这些问题,因为很多时候你并没有访问你想要的对象。

相反,Qt 提出的建议是在 QML 端建立连接,为此您必须使用 setContextProperty() 导出 C++ 对象。

在下面使用 QML 实现的示例中,我们创建了一个类,它有一个名为 mysignal 的信号,它每 5 秒触发一次以进行测试。该类的一个对象被导出到 QML 并连接,以便它从 QML 调用 js 函数

ma​​in.cpp

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

#include <QTimer>

class Helper: public QObject{
    Q_OBJECT
public:
    using QObject::QObject;
signals:
   void mysignal();
};

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    Helper helper;
    engine.rootContext()->setContextProperty("helper", &helper);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    QTimer timer;
    QObject::connect(&timer, &QTimer::timeout, [&helper](){
       emit helper.mysignal();
    });

    timer.start(5000);

    return app.exec();
}

#include "main.moc"

b.qml

import QtQuick 2.0

Item {
    id: it
    function connectionConfirmed() {
        myTimer.start()
        console.log("started timer")
    }
    Timer {
        interval: 1000; running: false; repeat: false
        id: myTimer
        onTriggered: {
            console.log("timer triggered")
        }
    }

    Connections{
        target: helper
        onMysignal: it.connectionConfirmed()
    }
}

最后,在 StackView 中,每次页面更改时都会创建和销毁项目。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多