Unsolved 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)); }
-
Hello @Steve-Fallows,
The conventional wisdom is to pass the "parameters" for your object as arguments on construction. In your case that means "pushing" theQQmlEngine *
through the constructor and saving it as a member.Kind regards.
-
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. -
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.