Qt - How to do what I want when another dialog is closed?
c++, qt, qt5, user-interface
Solution
Modify class A to emit signal when closed
If modifying the A widget is option, add a signal to it and override `closeEvent` or `hideEvent` and emit the new signal there. This is robust and you have complete control on what happens. However, rest of the answer is for case where, for whaever reason, you are unable or unwilling to mess with A and want a solution in class B.
Use the Qt signal for QObject deletion
If you can set `Qt::WA_DeleteOnClose` attribute on `A`, then simple way is to make `B::doSomething()` (note the common Qt method naming convention) a slot and connect `destroyed` signal of A instance to that.
B::B(QWidget *parent) : QDialog(parent), ui(new Ui::B)
{
a = new A();
a->setAttribute(Qt::WA_DeleteOnClose);
connect(a, SIGNAL(destroyed(QObject*)), SLOT(doSomething()));
a.show();
}
Of course this works even if you `delete a;` explicitly, and not automatically with the attribute.
Note: In this case, when the object may get deleted whenever, you should really use `QPointer` for the `a` pointer, to avoid accidentally referencing a dangling pointer.
Use Qt event filter
If you don't want to have the A instance deleted when it is closed (and re-created if it is needed again), then other way is to install event filter on the A instance, and detect the `closeEvent`. This has the potential problem, that the widget can reject the close event, and in any case `doSomething` is called before the closing. If this is a problem, it can be solved by using `QMetaObject::invokeMethod` static method to delay the `doSomething` (it must be slot or invokable method for this!) call to happen after close event is over and program returns to event loop. Then in `doSomething` check if `a` is really hidden. Instead of `QEvent::Close`, detecting `QEvent::Hide` might work well, too.
To implement this, override the virtual `eventFilter` method in B, something like this:
bool B::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::Close) { //or QEvent::Hide maybe
qDebug("QCloseEvent!");
// check that object is indeed this->a before calling this->doSomething()
if (qobject_cast<QObject *>(a) == obj) {
doSomething();
//alternative, make doSomething to be called later from event loop:
//QMetaObject::invokeMethod(this, "doSomething", Qt::QueuedConnection);
} else {
qDebug("...but the object is not what is expected, a bug?");
}
// do not block the event, just detect it
}
// proceed with standard event processing
return QObject::eventFilter(obj, event);
}
Then start listening events of an `A` instance with installEventFilter, something like:
B::B(QWidget *parent) : QDialog(parent), ui(new Ui::B)
{
a = new A();
installEventFilter(a);
a.show();
}
Problem
I have two classes `A` and `B`, here is a snippet in `B.h`: ``` #include "A.h" class B : public QDialog { Q_OBJECT public: void do_something(); private: A *a; } ``` and in `B.cpp`: ``` B::B(QWidget *parent) : QDialog(parent), ui(new Ui::B) { a = new A(); a.show(); } ``` So what should I do if I want to call `do_something()` when the `ui` of `A` is closed (by pressing `Alt-F4`, for example) ? Seems the way of `signal-slot` cannot apply here. Thanks a lot !