QML reports ReferenceError: XYZ is not defined on C++ object added to context

烈酒焚心 提交于 2019-12-24 00:54:55

问题


I've started learning QML recently (after trying it out a long time ago) and I'm stuck at the way Qt C++ code interacts with QML and vice versa.

I have a Counter which has the following header:

#include <QObject>
#include <QTimer>

class Counter : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int count
           READ getCount
           WRITE setCount
           NOTIFY signalCountChanged)
public:
    Counter(QObject *parent = Q_NULLPTR);
    int getCount();
    void setCount(int count);
signals:
    void signalCountChanged(int);
public slots:
    void slotStart();
private slots:
    void slotTimeout();
private:
    int count;
    QTimer *timer;
};

My main.cpp is as follows:

#include <QtGui/QGuiApplication>
#include <QtQml/QQmlContext>
#include <QtGui/QGuiApplication>
#include <QtQuick/QQuickItem>
#include <QtQuick/QQuickView>
#include "counter.h"

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

    qmlRegisterType<Counter>("org.qmlplayground.counter", 0, 1, "Counter");

    QQuickView view;
    view.setSource(QUrl(QStringLiteral("qrc:/main.qml")));

    QObject *viewO = dynamic_cast<QObject*>(view.rootObject());
    Counter c;
    // Register Counter instance as "counter" property of top level context so that it can be accessed from within the QML code (for example: set the value count)
    view.rootContext()->setContextProperty("counter", &c);

    QObject::connect(viewO, SIGNAL(signalStartCounter()),
            &c, SLOT(slotStart()));
    QObject::connect(viewO, SIGNAL(signalQuit()), &app, SLOT(quit()));
    view.show();

    return app.exec();
}

and finally part of my QML (the main.qml which is loaded in the QQuickView while the rest being an UI form):

import QtQuick 2.7
import QtQuick.Window 2.2

// Importing some JavaScript files
import "qrc:/loggingFunctions.js" as LOG
import "qrc:/parseFunctions.js" as PARSE

// Importing a Qt C++ custom module
import org.qmlplayground.counter 0.1

MainForm {
    property int countState: counter.count // ERROR HERE
    signal signalStartCounter()
    signal signalQuit()

    anchors.fill: parent

    textInputMouseArea.onClicked: {
        LOG.logger("Clicked! Selecting all text in text input field", "N")
        textInput.selectAll()
    }

    textInput.onAccepted: {
        if(textInput.text === "quit") signalQuit()//Qt.quit();
        if(textInput.text === "help") textInput.text = LOG.logger("Displaying help", "H");

        var res = PARSE.parseInput(textInput.text);
        if(res && (typeof res === 'object') && res.constructor === Array) {
            switch(res[0]) {
            case "fact":
                labelOutput.text = res[1];
                break;
            case "count":
                counter.count = res[1];
                signalStartCounter();
                break;
            }
        }
    }

    onCountStateChanged:
        console.log("Hello")

    textInput.onTextChanged:
        console.log("Text changed");
}

As you can see I've already tested two signals sent from my QML to my C++ code one being connected to my QGuiApplication's slot quit() and the other being connected to my counter's slot slotStart(). It works fine. It seems that the line

counter.count = res[1];

doesn't cause any issues (perhaps because it's JS and not QML?). Now I want to read the count value of my Counter instance and update my UI accordingly. If I'm not mistaken every QML property automatically gets a couple of things one of these being the onChanged method (event handler or whatever it's called).

When I run my code however I get

`qrc:/main.qml:21: ReferenceError: counter is not defined

I thought that doing view->rootContext()->setContextProperty("counter", &c); would be enough but it seems that I'm missing something. So the more general question would be how do I properly make a C++ object visible in QML context.


回答1:


This took me perhaps 2 hours to figure out (I posted my question when I was on the verge of commiting a suicide :D) but the answer was really obvious: how can I call for a property which hasn't been initialized yet? The solution to my problem is basically to move the setContextProperty() BEFORE I load the QML file:

// ...
QQuickView view;
Counter c;
view.rootContext()->setContextProperty("counter", &c);
view.setSource(QUrl(QStringLiteral("qrc:/main.qml")));
// ...

By doing so the property is first added to the root context of the view and after that the additional QML stuff is loaded but the counter property is still present). With the previous version of my code I was basically trying to access counter inside my QML file BEFORE I have added it as a property.



来源:https://stackoverflow.com/questions/38499869/qml-reports-referenceerror-xyz-is-not-defined-on-c-object-added-to-context

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!