Dynamic reload QML file from C++
-
Hi everyone! I have a problem with dynamic load of QML file. I’ve a QML plugin which has a component (C++). This component loads UI Component from QML (from qrc file of my plugin). I need reload this component when user change a few properties (one or more). I use this code for remove QML Content file:
if(m_contentItem) { m_contentItem->setParentItem(NULL); m_contentItem->deleteLater(); m_contentComponent->deleteLater(); }
But when user change property and this code is calls my application is crashed with this log:
Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Codes: KERN_INVALID_ADDRESS at 0x00000001000000c0 Exception Note: EXC_CORPSE_NOTIFY Termination Signal: Segmentation fault: 11 Termination Reason: Namespace SIGNAL, Code 0xb Terminating Process: exc handler [0] VM Regions Near 0x1000000c0: --> __TEXT 0000000109f39000-000000010a039000 [ 1024K] r-x/rwx SM=COW /Volumes/VOLUME/*/ShavSample.app/Contents/MacOS/ShavSample Thread 0 Crashed:: Dispatch queue: com.apple.main-thread 0 org.qt-project.QtQuick 0x000000010a132eec QQuickItem::setParentItem(QQuickItem*) + 44 1 libShavComponents_debug.dylib 0x00000001120aeb9d ShavNavigationView::recreateContentItemView() + 125 (shavnavigationview.cpp:52)
As you can see app is crashes on line where I try to remove parent. And I know why. This happens because my object m_contentItem has incorrect pointer to memory (was removed). But I don’t remove it in my code. Is exist something which I can use to check pointer in this case? What method(s) I need to use for remove QML component from C++ code?
-
@shav said in Dynamic reload QML file from C++:
where to do you get m_contentItem from in your C++ code?
You need to consider the ownership of the object before deleting it! -
@shav
you delete the object at the end of the pointer but do not remove the pointer.if(m_contentItem) { m_contentItem->setParentItem(NULL); m_contentItem->deleteLater(); m_contentItem = Q_NULLPTR; m_contentComponent->deleteLater(); }
this should at least fix your crash.
-
@raven-worx said in Dynamic reload QML file from C++:
@shav said in Dynamic reload QML file from C++:
where to do you get m_contentItem from in your C++ code?
You need to consider the ownership of the object before deleting it!Hi ,
Thanks for the reply! My code for get m_contentItem looks like:
QQmlEngine* engine = qmlEngine(this); if(!engine) { return; } m_contentComponent = new QQmlComponent(engine, this); QQmlEngine::setObjectOwnership(m_contentComponent, QQmlEngine::CppOwnership); m_contentComponent->loadUrl(QUrl("qrc:/qml/Navigation/ShavNavigationViewContent.qml"), QQmlComponent::PreferSynchronous); if(m_contentComponent->status()) { createNavigationViewContent(); } else { connect(m_contentComponent, &QQmlComponent::statusChanged, [this](QQmlComponent::Status status) { switch(status) { case QQmlComponent::Ready: { createNavigationViewContent(); break; } case QQmlComponent::Error: { if(m_contentComponent) { QString msg = "["+QString(metaObject()->className())+"] Error: "+m_contentComponent->errorString(); qDebug()<<msg; } break; } case QQmlComponent::Null: case QQmlComponent::Loading: { break; } } }); }
Where method createNavigationViewContent looks like:
if(m_contentComponent) { m_contentItem = qobject_cast<QQuickItem*>(m_contentComponent->create()); if(m_contentItem) { static int index = 0; m_contentItem->setObjectName(QString("ShavNavigationView_%1").arg(index)); ++index; m_contentItem->setParentItem(this); m_contentItem->setParent(this); QQmlEngine::setObjectOwnership(m_contentItem, QQmlEngine::CppOwnership); m_contentItem->setParent(this); m_contentItem->setProperty("footerComponent", QVariant::fromValue<QQmlComponent*>(m_footerComponent)); m_contentItem->setProperty("footer", m_footer); m_contentItem->setProperty("pageCount", m_pageCount); connect(m_contentItem, SIGNAL(pageCountDidChange()), this, SLOT(updatePageCount())); reloadContentItem(); qDebug()<<"m_contentItem: "<<m_contentItem; } else { QString msg = "["+QString(metaObject()->className())+"] ERROR: Content item component is NULL."; qDebug()<<msg; } } else { QString msg = "["+QString(metaObject()->className())+"] ERROR: Component is NULL."; qDebug()<<msg; }
-
@J.Hilk said in Dynamic reload QML file from C++:
@shav
you delete the object at the end of the pointer but do not remove the pointer.if(m_contentItem) { m_contentItem->setParentItem(NULL); m_contentItem->deleteLater(); m_contentItem = Q_NULLPTR; m_contentComponent->deleteLater(); }
this should at least fix your crash.
Hi J.Hilk,
Thanks for the reply! But I have a crash in line:
m_contentItem->setParentItem(NULL);
So, I can't apply Q_NULLPTR for my component.
-
@shav
I'm sorry, I should have written an more detailed answer.My asumption is that, for what ever reason, the function may be called twice, the first time its passing through like it should, and the 2nd time it crashed because there is no object at the end of the pointer to call setParentItem.
Have you debuged this line by line, or do you solely rely on the crash log?
On a side note, if you have pointers that are member variables, one should always make sure they point to something or to 0 to prevent any unnecessary errors, so my advise isn't useless ;-)