156

In Qt, what is the slot that corresponds to the event of the user clicking the 'X' (close) button of the window frame i.e. this button:

Close button of the window

If there isn't a slot for this, is there any other way to trigger a function after the user presses the close button?

Shravan
  • 2,809
  • 2
  • 18
  • 39

6 Answers6

203

If you have a QMainWindow you can override closeEvent method.

#include <QCloseEvent>
void MainWindow::closeEvent (QCloseEvent *event)
{
    QMessageBox::StandardButton resBtn = QMessageBox::question( this, APP_NAME,
                                                                tr("Are you sure?\n"),
                                                                QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes,
                                                                QMessageBox::Yes);
    if (resBtn != QMessageBox::Yes) {
        event->ignore();
    } else {
        event->accept();
    }
}


If you're subclassing a QDialog, the closeEvent will not be called and so you have to override reject():

void MyDialog::reject()
{
    QMessageBox::StandardButton resBtn = QMessageBox::Yes;
    if (changes) {
        resBtn = QMessageBox::question( this, APP_NAME,
                                        tr("Are you sure?\n"),
                                        QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes,
                                        QMessageBox::Yes);
    }
    if (resBtn == QMessageBox::Yes) {
        QDialog::reject();
    }
}
Jason Sundram
  • 12,225
  • 19
  • 71
  • 86
asclepix
  • 7,971
  • 3
  • 31
  • 41
  • 1
    You may want to also use `setAttribute(Qt::WA_QuitOnClose);` for MainWindow. – Borzh Nov 22 '15 at 17:14
  • Are you sure that subclassing QDialog will not call `closeEvent`? It works for me, and the documentation of [QCloseEvent](http://doc.qt.io/qt-5/qcloseevent.html) says that *The event handler QWidget::closeEvent() receives close events* and QDialog is also a Widget right? Or is it related to older Qt version (<5.x) somehow? – Dimitri Podborski Mar 30 '16 at 10:17
  • 2
    @incBrain Even in Qt 4.8 the 'X' button calls `closeEvent` in a QDialog, but if the user press _Esc_ on the keyboard the QDialog is closed without calling `closeEvent`. – asclepix Mar 31 '16 at 09:57
  • @asclepix thanks for clarification. So basically overwriting `reject` function would be the right move to solve this problem. I've found this sentence in the documentation: *In order to modify your dialog's close behavior, you can reimplement the functions accept(), reject() or done(). The `closeEvent()` function should only be reimplemented to preserve the dialog's position or to override the standard close or reject behavior* – Dimitri Podborski Mar 31 '16 at 10:25
  • Another way would be to connect to *rejected* signal of QDialog. – JeFf Mar 14 '18 at 14:42
22

Well, I got it. One way is to override the QWidget::closeEvent(QCloseEvent *event) method in your class definition and add your code into that function. Example:

class foo : public QMainWindow
{
    Q_OBJECT
private:
    void closeEvent(QCloseEvent *bar);
    // ...
};


void foo::closeEvent(QCloseEvent *bar)
{
    // Do something
    bar->accept();
}
waldyrious
  • 3,683
  • 4
  • 33
  • 41
Shravan
  • 2,809
  • 2
  • 18
  • 39
16

You can attach a SLOT to the

void aboutToQuit();

signal of your QApplication. This signal should be raised just before app closes.

Sebastian Lange
  • 3,879
  • 1
  • 19
  • 38
12

also you can reimplement protected member QWidget::closeEvent()

void YourWidgetWithXButton::closeEvent(QCloseEvent *event)
{
    // do what you need here
    // then call parent's procedure
    QWidget::closeEvent(event);
}
Alexander
  • 139
  • 1
  • 2
0

To capture the event of the close button being pressed without deriving from QWidget and the sort, you could use an event filter.

Here's a simple demonstration, using a simple application that displays a QWidget:

If you use QWidget itself, you need to capture QEvent::Close:

#include "myEventFilter.h"
#include <QApplication>
#include <QWidget>

int main(int argc,char*argv[])
{
    QApplication a(argc, argv);
    
    w.installEventFilter(filter);
    
    QWidget *w = new QWidget();

    //install the event filter on the widget
    w->installEventFilter(filter);

    w->show();

    return a.exec();
}

Event filter:

#ifndef MYEVENTFILTER_H
#define MYEVENTFILTER_H

#include <QObject>
#include <QDebug>
#include <QEvent>

class myEventFilter : public QObject
{
    Q_OBJECT

public:
    myEventFilter (QObject *parent = nullptr) {}

protected:
    bool eventFilter(QObject * obj, QEvent * event) override
    {
        if (event->type() == QEvent::Close)
        {
            //handle the event here
            qDebug()<<"out";
           //In case you need the QWidget itself 
           QWidget *w = static_cast<QWidget*>(obj);
        }

        return QObject::eventFilter(obj, event);
    }
};

#endif // MYEVENTFILTER_H

If you use QApplication's object, you need to capture QEvent::Quit:

#include <QApplication>
#include "myEventFilter.h"

int main(int argc,char*argv[])
{
    QApplication a(argc, argv);

    QWidget *w = new QWidget();

    myEventFilter *filter = new myEventFilter();

    //install the event filter on QApplication object
    a.installEventFilter(filter);

    w->show();

    return a.exec();
}

Event filter

#ifndef MYEVENTFILTER_H
#define MYEVENTFILTER_H

#include <QObject>
#include <QDebug>
#include <QEvent>
#include <QLineEdit>

class myEventFilter : public QObject
{
    Q_OBJECT

public:
    myEventFilter (QObject *parent = nullptr) {}

protected:
    bool eventFilter(QObject * obj, QEvent * event) override
    {
        if (event->type() == QEvent::Quit)
        {
            //handle the event here as well
            qDebug()<<"out";
        }

        return QObject::eventFilter(obj, event);
    }
};

#endif // MYEVENTFILTER_H

0

The simple way to close properly using QCloseEvent.

void MainWindow::closeEvent (QCloseEvent *)
{
    QCoreApplication::quit();
}
Shaiful Islam
  • 335
  • 2
  • 12