yakiang
yakiang

Reputation: 1634

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

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 !

Upvotes: 6

Views: 3741

Answers (3)

Parker Coates
Parker Coates

Reputation: 9398

The QDialog::finished(int) signal is probably sufficient to find out when a dialog has been closed.

There are ways to hide a dialog without finished being emitted, but they don't come up in typical QDialog usage.

Upvotes: 0

hyde
hyde

Reputation: 62777

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();
}

Upvotes: 7

Zlatomir
Zlatomir

Reputation: 7034

If you can't use a modal window (or dialog) than you have a little more work, you'll need to subclass QWidget (or QDialog or other QWidget derived class, whatever you need) and override QWidget::closeEvent (for class A) and from here call a method of the parent (i suppose a will be a child of this in your code: a = new A(this);) or code your own signal/slot.

And if you decide to use a modal dialog, the code becomes simpler, see example code in the QDialog's documentation.

Upvotes: 3

Related Questions