QObject gets destroyed after being put into QML variable - qt

Today I've faced strange bug in our program. The object of a class inherited from QObject was being deleted by event with type QEvent::DefferedDelete, while nobody could possibly send it.
It was passed into QML as QVariant:
// cpp:
Q_INVOKABLE QVariant currentDevice_v() const {
return QVariant::fromValue(_current);
}
// qml:
Component.onCompleted: {
curDevice = devicesModel.currentDevice_v()
#...
}
Without that qml line everything worked well - nothing produces delete event.

What I've figured out that if I set the parent of that QObject before I pass it into QML, then it doesn't get deleted. So, I've concluded that passing unparented QObject into QML scope makes that scope become a parent of QObject and call its destructor after scope ends.
Sharing this out, as I haven't found an answer anywhere. But while writing this post I've found similar unanswered issue: Qt5.6 QML, why are dynamic models destroyed after garbage collection?

Related

Is there any QML window UI fully constructed signal?

I've found this, but it is only about QWidget based project. What about ApplicationWindow components in QML?
Finally I've connected to frameSwapped signal of the main top-level QQuickWindow of my application. It is called right after each repainting is done. So, after first repainting, my slot would be called, and I will start to really load the data (what is rather slow). Inside this slot I'm destroying this connection, so I don't slow down the application.
//main.cpp
QQuickWindow* mainWindow =
qobject_cast<QQuickWindow*>(engine.rootObjects().first());
QMetaObject::Connection loadingFinished =
QObject::connect(mainWindow, SIGNAL(frameSwapped()),
&controller, SLOT(construct()));
controller.setConnection(loadingFinished);
//Controller.cpp
void Controller::construct() // this is slot
{
// some really long operation
disconnect(*m_loadingFinished);
}
Hope it will be helpful for someone.

Why do qobject_cast and dynamic_cast fail in a slot connected to QWidget::destroyed?

I have a class Subclass, subclassed from QObject. I want to know when the item is deleted, so I connected this slot to the QWidget::destroyed() signal inherited by Subclass. But when I try to cast the argument to with qobject_cast, I get a zero result. The same result obtains from C++'s dynamic_cast. Why?
void MyClass::mySlot( QObject * item )
{
qobject_cast<Subclass*>(item); // returns zero, even though item is a Subclass*
}
The reason is that by the time QObject::destroyed() is emitted, your derived class Subclass has already been destroyed. This is implied by the C++ order of destruction. Also, this question deals with a similar issue.
To get around this, you could either use C-style pointer casting (which is dispreferred), or rewrite your code to use a QObject instead.

Why aren't QObjects deleted twice, if they are class-members and childs at the same time?

If a QObject is a member of a class (not created with the new-operator) and at the same time a child of the class-instance, it should be deleted twice, because all childs of the class-instance are deleted and in the desctructor of the class all class-members are deleted. Hence, the program should crash. But this doesn't happen, so Qt somehow must detect this double-relationship. But does this really happen? And if yes, how does it work?
Here is an example:
class MyWindow : public QMainWindow {
Q_OBJECT
public:
MyWindow();
QLabel label;
};
MyWindow::MyWindow() : label(this) {}
When an instance of MyWindow is destroyed, label should be deleted twice because it is a member AND a child of MyWindow. But this doesn't happen and it seems safe to do this. But how does it work?
This works in this case, because of the order of deletion:
~MyWindow() is called first, which destroys the label. The label's ~QObject() destructor removes the object from the parent's list of children.
After ~MyWindow(), at some point the MyWindow's ~QObject() destructor is called, which delete's the window's children. However, as the label pointer was already removed from the list of children, there is no attempt to delete the label again.
According to the Qt documentation: You can also delete child objects yourself, and they will remove themselves from their parents. I take that to mean that the child is responsible for the detachment as a part of its destructor. From this page.
Also, it may be useful to note that the order of destruction in C++ specifies that member destructors are called prior to base class destructors, see here. So label will remove itself prior to the MyWindow needing to remove it.

Setting QObject ownship for QWebFrame javascript

I have a QObject that exists in a QWebFrame javascript environment through the addToJavaScriptWindowObject interface. This QObject has Q_INVOKABLE methods that return more QObject pointers (like a factory) that are used within javascript. Qt automatically turns these QObject pointer into objects that can be invoked in the calling javascript enviornment.
The issue is, I want to have javascript assume ownership of this QObject. The current behavior is that the C++ environment retains ownership.
I've dealt with QScriptEngine directly in the past where the QObject factory object holds a pointer to the QScriptEngine object and creates new objects using QScriptEngine::newQObject with a QScriptEngine::ScriptOwnership argument. This works perfectly. But for the QWebFrame javascript engine, the engine is buried inside of the QWebFrame and inaccessible.
How can I return QObject's to a QWebFrame javascript environment and have javascript assume ownship of that object?

qt inherited signal won't reach to slot

here's the code of my problem
class Base : QThread
{
Q_OBJECT
virtual void run() = 0;
signals:
void Ping(int);
};
class Derived : public Base
{
void run()
{
emit Ping(42);
}
}
the signal(42) won't reach/call to slots. what's wrong?
thanks in advance.
Did that 100 times, it does work. Are you sure your base class is properly MOC'ed ? (i.e. defined in a file contained in HEADERS section of .pro) Also when connecting your signal, check the return status of QObject::connect (it's a boolean). A good practice is something like that
bool r=false;
r=QObject::connect(pObj1,SIGNAL(signalStuff()),pObj2,SLOT(gotStuff()));
Q_ASSERT(r);
As Liz noticed, if something went wrong in your connect, you can check the traces to know what happened.
I can also note :
you don't have to redefine run in your base class, it's already defined by QThread
Common pitfall with QThread: Base class and Derived class belong to the thread which created them, not in the newly created thread
you don't connect your signal to any slot in your sample, so it won't trigger anything (I suppose it's done elsewhere)
your class Derived lacks the final ;
EDIT:
Edited to take into account liz' interesting comment.
I came upon the same problem but managed to find solution. The problem in my case wasnt the inheritance (even tho i did emit from derived class).
The problem was the code calling emit signal was execute BEFORE the code connecting signal with slot. Therefor both signal was emitted and signal-slot connection worked fine, but the code in the slot wasnt executed because emit happened before connecting the slot to signal.
Maybe that helps someone in the future.
I think you are trying to connect signal and slot from different threads.
Did you read this article?

Resources