How *should* I get the QML Application Engine?



  • I am using the following C++ code to append text strings to a QML TextArea. The 'else' flavor of the code works, but relies on a global variable to get the QQmlApplicationEngine. The 'if' flavor gets the engine another way, but as a QQmlEngine not a QQmlApplicationEngine. However it always returns a nullptr for the contextObject of the rootContext.

    Is there an idiomatic way of getting the application engine? Every example I find is a trivial program with all the code in main. I'd prefer to avoid a global, but I can live with it if that's the "normal" way.

    void appendTextOutput(const QString &additionalText)
    {
    

    #if 0

        QQmlContext *currentContext = QQmlEngine::contextForObject(this);
        QQmlEngine *engine = currentContext->engine();
        std::cout << "Engine object: " << g_engine->objectName().toStdString() << std::endl;
    
        QQmlContext* rootContext = engine->rootContext();
        QObject* object = rootContext->contextObject();
        if (object == nullptr)
        {
            std::cout << "Drat! no contextobject" << std::endl;
        }
    
        QObject *consoleTextObject = object->findChild<QObject *>("ConsoleTextObject");
    

    #else

        std::cout << "Engine object: " << g_engine->objectName().toStdString() << std::endl;
        QObject* consoleTextObject = g_engine->rootObjects().first()->findChild<QObject*>("ConsoleTextObject");
    

    #endif

        QMetaObject::invokeMethod(consoleTextObject, "append", Q_ARG(QString, additionalText));
    }

  • Qt Champions 2016

    Hello @Steve-Fallows,
    The conventional wisdom is to pass the "parameters" for your object as arguments on construction. In your case that means "pushing" the QQmlEngine * through the constructor and saving it as a member.

    Kind regards.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Looks like you're doing things in reverse logic. Why not create an object that generates the data, add it to the root context of your engine, and connect it to your TextEdit ?



  • @kshegunov
    Thanks for the info. I am well aware of that principle for C++. But being new to QML, not sure how to apply it. The C++ class is registered via qmlRegisterType and instantiated in QML. AFAICT, there is no way to pass parameters to the constructor. Nor do I see how QML would get hold of the QQmlEngine pointer.


  • Qt Champions 2016

    @Steve-Fallows

    But being new to QML

    Me too, but now I think I understand what you're trying to achieve. I'd try something like this:

    QQmlApplicationEngine * engine = qobject_cast<QQmlApplicationEngine *>(qmlEngine(this));
    
    Q_ASSERT(engine);
    if (!engine)
        return;
    
    const QObjectList rootObjectsList = engine->rootObjects();
    for (QObject * rootObject : rootObjectsList)  {
        QObject * consoleTextObject = rootObject->findChild<QObject *>("ConsoleTextObject");
        if (!consoleTextObject)
            continue;
        // ...
    }
    

    or something like this:

    QQmlEngine * engine = qmlEngine(this);
    
    Q_ASSERT(engine);
    if (!engine)
        return;
    
    QObject * consoleTextObject = engine->rootContext()->findChild<QObject *>("ConsoleTextObject");
    

    I hope that helps.
    Kind regards.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.