Wurgl
12th January 2011, 23:22
I have here a cut-down example of a crash indirect caused by setAttribute(Qt::WA_DeleteOnClose) and I do not know a nice way to prevent it.
To reproduce:
Compile that snipplet and start it. Then click into the window which shows up (it contains a pushbutton) and after that close the window (where you clicked into) by clicking on the bix X in the title line.
The crash happens because that attribute "Qt::WA_DeleteOnClose" calls the destructor of the main window. Since the small dialog has a parent, it is deleted too. Now it has its own exec() call where it loops.
Now I do not want to drop that "Qt::WA_DeleteOnClose" line, because this would mean unused memory which is still allocated and the application grows and grows ...
I also would like to show the child dialog centered above the main window and since I am lazy, is simple use the parent widget as a parameter during start.
I also would like to avoid a modal dialog.
If I could drop one of these three requirements, the crash would go.
One way could be to clear the parent of the child window. This would mean a lot of coding, since I need to know which child windows exists (there could be many, not just one), but as i wrote: I am lazy ...
Another way could be to drop the exec() call in the opened dialog, which would mean rearranging the logic in the caller, again this needs to handle a collection of a opened subdialogs ... I don't like that, since I am lazy.
Does anyone have another idea?
#include <Qt/qapplication.h>
#include <Qt/qpushbutton.h>
#include <Qt/qmainwindow.h>
#include <Qt/qdialog.h>
#include <Qt/qlabel.h>
#include <Qt/qlayout.h>
#include <Qt/qevent.h>
class SomeMainWin : public QMainWindow {
Q_OBJECT;
public:
SomeMainWin();
virtual ~SomeMainWin();
virtual void closeEvent(QCloseEvent *event);
QPushButton *_openDialog;
public slots:
void openAnDialog();
};
class SomeDialog : public QDialog {
public:
SomeDialog(QWidget *parent);
virtual ~SomeDialog();
int run();
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
SomeMainWin *myMainWin = new SomeMainWin();
myMainWin->show();
app.exec();
exit(0);
}
SomeMainWin::SomeMainWin()
{
setAttribute(Qt::WA_DeleteOnClose);
_openDialog = new QPushButton("Open");
connect(_openDialog, SIGNAL(clicked()), this, SLOT(openAnDialog()));
setCentralWidget(_openDialog);
}
SomeMainWin::~SomeMainWin()
{
}
void SomeMainWin::closeEvent(QCloseEvent *event)
{
event->accept();
}
void SomeMainWin::openAnDialog()
{
SomeDialog SomeDialog(this);
if(SomeDialog.run() == QDialog::Accepted) {
// ... do this an that
}
}
SomeDialog::SomeDialog(QWidget *parent)
: QDialog(parent)
{
QVBoxLayout *layout = new QVBoxLayout();
setLayout(layout);
QLabel *label = new QLabel("Hello");
layout->addWidget(label);
}
SomeDialog::~SomeDialog()
{
}
int SomeDialog::run()
{
show();
exec();
}
#include "main.moc"
the crash looks like this (it is Suse Linux)
$ ./a.out
QObject: Do not delete object, 'unnamed', during its event handler!
*** glibc detected *** ./a.out: double free or corruption (out): 0x00007fffc1a87630 ***
To reproduce:
Compile that snipplet and start it. Then click into the window which shows up (it contains a pushbutton) and after that close the window (where you clicked into) by clicking on the bix X in the title line.
The crash happens because that attribute "Qt::WA_DeleteOnClose" calls the destructor of the main window. Since the small dialog has a parent, it is deleted too. Now it has its own exec() call where it loops.
Now I do not want to drop that "Qt::WA_DeleteOnClose" line, because this would mean unused memory which is still allocated and the application grows and grows ...
I also would like to show the child dialog centered above the main window and since I am lazy, is simple use the parent widget as a parameter during start.
I also would like to avoid a modal dialog.
If I could drop one of these three requirements, the crash would go.
One way could be to clear the parent of the child window. This would mean a lot of coding, since I need to know which child windows exists (there could be many, not just one), but as i wrote: I am lazy ...
Another way could be to drop the exec() call in the opened dialog, which would mean rearranging the logic in the caller, again this needs to handle a collection of a opened subdialogs ... I don't like that, since I am lazy.
Does anyone have another idea?
#include <Qt/qapplication.h>
#include <Qt/qpushbutton.h>
#include <Qt/qmainwindow.h>
#include <Qt/qdialog.h>
#include <Qt/qlabel.h>
#include <Qt/qlayout.h>
#include <Qt/qevent.h>
class SomeMainWin : public QMainWindow {
Q_OBJECT;
public:
SomeMainWin();
virtual ~SomeMainWin();
virtual void closeEvent(QCloseEvent *event);
QPushButton *_openDialog;
public slots:
void openAnDialog();
};
class SomeDialog : public QDialog {
public:
SomeDialog(QWidget *parent);
virtual ~SomeDialog();
int run();
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
SomeMainWin *myMainWin = new SomeMainWin();
myMainWin->show();
app.exec();
exit(0);
}
SomeMainWin::SomeMainWin()
{
setAttribute(Qt::WA_DeleteOnClose);
_openDialog = new QPushButton("Open");
connect(_openDialog, SIGNAL(clicked()), this, SLOT(openAnDialog()));
setCentralWidget(_openDialog);
}
SomeMainWin::~SomeMainWin()
{
}
void SomeMainWin::closeEvent(QCloseEvent *event)
{
event->accept();
}
void SomeMainWin::openAnDialog()
{
SomeDialog SomeDialog(this);
if(SomeDialog.run() == QDialog::Accepted) {
// ... do this an that
}
}
SomeDialog::SomeDialog(QWidget *parent)
: QDialog(parent)
{
QVBoxLayout *layout = new QVBoxLayout();
setLayout(layout);
QLabel *label = new QLabel("Hello");
layout->addWidget(label);
}
SomeDialog::~SomeDialog()
{
}
int SomeDialog::run()
{
show();
exec();
}
#include "main.moc"
the crash looks like this (it is Suse Linux)
$ ./a.out
QObject: Do not delete object, 'unnamed', during its event handler!
*** glibc detected *** ./a.out: double free or corruption (out): 0x00007fffc1a87630 ***