Unsolved Correct way to close a modeless QDialog?
-
I‘m not familiar with the python side of Qt,
But since it‘s a wraper around the c++ part I would guess you can specify in your connection setup the connection type.
By default this is on auto, that defaults by same thread connections to a DirectConnection,
if you explicitly connect your slot with a QueuedConnection, your slot should be executed well after all the cleanup.
Maybe that‘s already enough for your case ?
-
@J.Hilk
Hi, I have no idea what you mean?!I want a signal when a dialog gets closed. There doesn't seem to be one. I don't see any connection to what you have written about connections? :)
-
I've told you what you need to do...good luck with that
-
@JonB
you said the finished signal comes slighlty to early for your purpose,so my suggestion connect your slot to finished with the QueuedConnecten argument
https://doc.qt.io/qt-5/qt.html#ConnectionType-enumand from prevoius topics I assumed, you’re still doing pyqt work, but I might be mistaken here 🙈
-
Hi,
Does it happen if you use a dummy dialog ?
What are you doing in it ? -
@J.Hilk
Ah, OK, I get your drift now.@SGaist
I warned it gets complicated! The modeless dialog hosts aQWebEnginePage
. The SIGSEGV backtrace shows it's somewhere in destructors fromQWebEnginePage
/View
stuffYou've both asked, so: what I have here is a Python/PyQt problem. As briefly as possible: I need to create and show a modeless dialog, with no parent ("fully" modeless), via
QDialog.show()
. In Python/PyQt I must maintain a reference to such a dialog --- if I don't assign it to a "global variable" to keep a reference Python/PyQt will garbage collect and immediately destroy the unreferenced dialog. I keep that in a singleton class.When the dialog closes this reference must be cleared, to release the Python reference. So I need a reliable signal to tell me when it gets closed. Outline:
singleton.modelessDialog = QDialog(parent=None) singleton.modelessDialog.finished.connect(singleton_modeless_closed) singleton.modelessDialog.show() def singleton_modeless_closed() singleton.modelessDialog = None
From the signals available to me, the best I could see is
finished
. But when I set the reference toNone
in that slot, as shown above, there is a (later?) SIGSEGV in the modeless dialog, down inQWebEnginePage
destructors. I'm releasing the Python reference during thefinished
signal, I'm guessing that destroys stuff while it's still in use or whatever.So I wanted a signal which comes later, when the dialog gets closed. I expected a
closed
signal, but it appears Qt does not supply one. The stackoverflow post, and @Kent-Dorfman, seem to be confirming this.If you know better, or a better way I can achieve this using Python, please explain. I think the crashing is a Python behaviour issue, you probably wouldn't get it in C++. You could probably go:
singleton.modelessDialog.deleteLater(); singleton.modelessDialog = nullptr;
-
What about keep that dialog as a class variable ? That should keep it alive and then you can try to enable the Qt. WA_DeleteOnClose widget attribute.
Hope it helps
-
@SGaist
It happens to be a singleton variable, same effect as a class variable. It's not that --- it's when I set it toNone
that is problematic.We have come full-circle! I am currently able to use
Qt.WA_DeleteOnClose
on the dialog so can connect toQWidget.destroyed
, instead ofQDialog.finished
, as the signal to indicate when I can clear the reference. That does not produce the SIGSEGV. But relies onQt.WA_DeleteOnClose
, which can be good or bad for dialogs. -
@Kent-Dorfman said in Correct way to close a modeless QDialog?:
@JonB said in Correct way to close a modeless QDialog?:
I need a signal whenever a (modeless) QDialog gets "closed", whether by user interaction or programmatic close()/done()/whatever.
void QWidget::closeEvent(QCloseEvent *event)
Then subclass the dialog, and override the closeEvent() method. emit your custom signal AFTER doing the default closeEvent() code.
As I said, I need to know when the dialog is "closed" regardless of how. I have spent ages only to discover that
closeEvent
does not get emitted if code callsQDialog::accept
/reject
/done()
, non-intuitive and non-documented... :( Further, it does not get called if the user clicks Escape to close, though it does get called if user clicks the X to close, or if code callsclose()
explicitly, only those two cases. Crazy.Other than working with the
destroyed
signal I'm finding it unreliable/hard to detectQDialog
closure...? -
I did some checking and you are right about closeEvent(). It doesn't always get called. However, I did a short test program and the virtual void hideEvent() always seems to be called when anything derived from the QWidget base class closes (immediately after the window system closes the window).
class MyDialog: public QFileDialog { Q_OBJECT public: MyDialog(); void hideEvent(QHideEvent* evt); };
MyDialog::MyDialog(): QFileDialog() {} void MyDialog::hideEvent(QHideEvent* evt) { std::cout << "hideEvent()" << std::endl; QFileDialog::hideEvent(evt); }
-
@Kent-Dorfman
You are kind to look at this, but I'm afraid no cigar :( This time I thinkhideEvent
is way too often for what I want!Note: A widget receives spontaneous show and hide events when its mapping status is changed by the window system, e.g. a spontaneous hide event when the user minimizes the window
Because I am Python/PyQt, I need to know when I can release the global reference I must keep to a shown modeless dialog. If I do it too early I will "crash" because the dialog is still in use; if I do it too late/miss the event I will not free the resource.
This is proving surprisingly difficult :( If you are in C++ it corresponds to:
globalModeless = new QDialog(nullptr); globalModeless.show(); ...
Now the question is: when exactly are you going to call
delete globalModeless
, in response to the user/code permanently closing the dialog, by any means? Assume that you are not usingQt::WA_DeleteOnClose
flag .