Quitting, assert runtime error - child, parent
-
Dear all,
I'm working on a desktop client monitoring a wind turbine.
I am programming components in c++ that creates QQmlComponent from a .qml file and then creates a QObject and link it with my window's content Rectangle.When i call Qt.quit() from the QML, i have a runtime error and don't really know from where it is coming.
I thought i was from the parent - child link but nothing resolved it.What do you think of that ?
Is there somebody having the same issue ? (I found nothing or nothing helping on google so i think i made something wrong that is evident to Qt programmers).Error :
ASSERT: "childItems.contains(child)" in file items\qquickitem.cpp, line 2953 Invalid parameter passed to C runtime function. Invalid parameter passed to C runtime function. ASSERT: "!m_thread.isRunning()" in file qqmldebugserver.cpp, line 655 Invalid parameter passed to C runtime function. Invalid parameter passed to C runtime function.
Some time this error is replaced by the CoreIndex >= 0 assert
LogInForm.h
#ifndef LOGINFORM_H # define LOGINFORM_H # include <QObject> # include <QQmlComponent> # include <QQmlEngine> # include <QUrl> # include <QQuickItem> # include <QtQuick> # include <QQuickItem> # include <iostream> class LogInForm : public QObject { Q_OBJECT public: // Constructor explicit LogInForm(QObject *parent = 0, QQmlEngine *engine = 0); signals: public slots: protected slots: void onViewStatusChanged(QQmlComponent::Status status); void onSubmitForm(); protected: QString _qmlSrcUrl; QQmlEngine *_engine; QQmlComponent *_component; QObject *_qmlComponent; }; #endif // LOGINFORM_H
LogInForm.cpp
#include "cpp/headers/qtViews/loginform.h" LogInForm::LogInForm(QObject *parent, QQmlEngine *engine) : QObject(parent) { // Set the QML Source File Path/Url _qmlSrcUrl = "qrc:/qml/logInForm.qml"; // Get the QQmlEngine if (engine != 0){ _engine = engine; } else { _engine = new QQmlEngine(); } // Create a QQmlComponent Object from QML Source File _component = new QQmlComponent(_engine, QUrl(_qmlSrcUrl)); std::cout << _component->status() << std::endl; QList<QQmlError> errors = _component->errors(); foreach (QQmlError e, errors) { std::cout << "(" << e.line() << ", " << e.column() << ") :: " << qPrintable(e.description()) << std::endl << qPrintable(e.toString()) << std::endl; } // Track when the component is ready if(_component->status() == QQmlComponent::Ready) { onViewStatusChanged(QQmlComponent::Ready); } else { connect(_component, SIGNAL(statusChanged(QQmlComponent::Status)), this, SLOT(onViewStatusChanged(QQmlComponent::Status))); } } void LogInForm::onViewStatusChanged(QQmlComponent::Status status) { QQuickItem *i = Q_NULLPTR; if(status == QQmlComponent::Ready) { // Create a Qml Object from the created _component _qmlComponent = _component->create(); i = qobject_cast<QQuickItem*>(_qmlComponent); // Set Cpp ownership to avoid javascript garbage collector to delete the object QQmlEngine::setObjectOwnership(i, QQmlEngine::CppOwnership); // Set parent and visual parent i->setParentItem(qobject_cast<QQuickItem*>(this->parent())); //i->setVisible(true); connect( _qmlComponent, SIGNAL(submitForm()), this, SLOT(onSubmitForm())); } } void LogInForm::onSubmitForm() { QString username = _qmlComponent->property("username").toString(); QString password = _qmlComponent->property("password").toString(); QString serverAddress = _qmlComponent->property("serverAddress").toString(); QString serverName = _qmlComponent->property("serverName").toString(); }
Main.cpp
#include <QApplication> #include <QQmlApplicationEngine> #include "cpp/headers/qtViews/loginform.h" #include <iostream> int main(int argc, char *argv[]) { QApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml"))); QObject *mainWindow = engine.rootObjects().first(); if (!mainWindow){ std::cerr << "Main :: mainWindow not found !" << std::endl; return EXIT_FAILURE; } QObject *contentRectangle = mainWindow->findChild<QObject*>("contentRectangle"); if (!contentRectangle){ std::cerr << "Main :: contentRectangle not found !" << std::endl; return EXIT_FAILURE; } QObject *logInForm = new LogInForm(contentRectangle, &engine); return app.exec(); }
Thank you a lot for helping,
Olivier :) -
To avoid errors in future, I strongly recommend setting all pointers to nullptr in your header or contructor initializer list. It's not a problem here, but it can quickly become one as the code evolves. Or use smart pointers.
This is unusual way of creating QML interfaces, but looks very cool! :-)
Regarding the errors - I have to say up front that I don't know the answer. I have only a few suspicions, but nothing certain:
- object ownership: QObjects delete their children when they are deleted. _qmlComponent's visual parent is contentRectangle, but it's QObject parent seems to be the _component. Not sure if that is entirely correct
- check if all the objects live in the same thread (with QObject::thread() or was it threadId()?) - maybe that will point you towards the problem
- are you 100% sure that contentRectangle is a QQuickItem? You don't verify if the cast works in
LogInForm::onViewStatusChanged
childItems.contains(child)
LogInForm is a child of contentRectangle, and so is the _qmlComponent, but only only one of these is a QQuickItem. Maybe the parent object has a problem with that?- try running it via thread sanitizer and address sanitizer, maybe they will show mor eprecisely what fails
-
main.qml - What is the top level item ? Is it window or Item ?
loginform.qml - What is top level item ? Is it window or Item ?This is typical issue of object deleted already is getting delete due to parent child relation ship ?