Qt - How to do what I want when another dialog closes?

I have two classes A and B , here is a snippet in Bh :

 #include "Ah" class B : public QDialog { Q_OBJECT public: void do_something(); private: A *a; } 

and 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 ui of A closed (for example, by pressing Alt-F4 )? It seems that the signal-slot method is not applicable here.
Thank you very much!

+6
source share
2 answers

Change class A to emit a signal when closing

If modifying widget A is an option, add a signal to it and override closeEvent or hideEvent and issue a new signal there. It is sustainable and you have full control over what is happening. However, the rest of the answer is for the case when for some reason you cannot or do not want to contact A and want to get a solution in class B.

Use Qt Signal to Remove QObject

If you can set the Qt::WA_DeleteOnClose attribute to A , then an easy way is to make B::doSomething() (note the general Qt naming convention) slot and connect the destroyed instance signal to this.

 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 an attribute.

Note. In this case, when the object can be deleted every time, you should really use QPointer for pointer A to avoid accidentally referencing the dangling pointer.

Use Qt Event Filter

If you do not want instance A to be deleted when it was closed (and re-created if needed again), another way is to set an event filter on instance A and detect closeEvent . This is a potential problem that the widget may reject the close event, and in any case, doSomething is called before closing. If this is a problem, it can be solved by using the QMetaObject::invokeMethod static method to delay doSomething (it must be a slot or invokable method for this!), The call will occur after the completion event is completed, and the program will return to the event loop. Then in doSomething check if A really hidden. Instead of QEvent::Close detecting QEvent::Hide may also work.

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 to A events with installEventFilter , for example:

 B::B(QWidget *parent) : QDialog(parent), ui(new Ui::B) { a = new A(); installEventFilter(a); a.show(); } 
+6
source

If you cannot use a modal window (or dialog) than you have a little more work, you need to subclass QWidget (or QDialog or another QWidget-based class, whatever you need) and override QWidget :: closeEvent ( for class A) and from here call the parent method (suppose a is a child of this in your code: a = new A (this);) or encode your own signal / slot.

And if you decide to use a modal dialog, the code will become simpler, see the code example in the QDialog documentation.

+3
source

Source: https://habr.com/ru/post/959244/


All Articles