Destructor called twoice
-
Hi all!
I am developing a Qt application. This application consists of several widgets, one of which I want to be able to remove from the layout with a call from an action in a context menu. The widget that I created has a signal that is emitted when there is a request to delete the custom widget that I created. Then, the main application is connected to this signal and removes the widget from the layout. The problem is that, when I emmit this signal by pressing a push button of my custom widget the signal is emmited and the custom widget is propperly removed. However, when I emit the same signal from the action of the context menu, the destructor of my custom widget is called two times. Here is a simplified example of what i want to do.
The custom widget looks like:
#ifndef BUTTON_H #define BUTTON_H #include <QWidget> namespace Ui { class Button; } class Button : public QWidget { Q_OBJECT public: explicit Button(int n, QWidget *parent = 0); ~Button(); private slots: void on_pushButton_clicked(); void on_actionRemove_triggered(); signals: void remove(Button* button); private: Ui::Button *ui; }; #endif // BUTTON_H
#include "button.h" #include "ui_button.h" Button::Button(int n, QWidget *parent) : QWidget(parent), ui(new Ui::Button) { ui->setupUi(this); ui->pushButton->setText("Remove button "+QString::number(n)); addAction(ui->actionRemove); } Button::~Button() { delete ui; } void Button::on_pushButton_clicked() { emit remove(this); } void Button::on_actionRemove_triggered() { emit remove(this); }
The main application looks like:
#ifndef BUTTONSTACK_H #define BUTTONSTACK_H #include <QWidget> #include "button.h" namespace Ui { class ButtonStack; } class ButtonStack : public QWidget { Q_OBJECT public: explicit ButtonStack(QWidget *parent = 0); ~ButtonStack(); private slots: void on_addButton_clicked(); void remove(Button* button); private: Ui::ButtonStack *ui; int total_buttons; }; #endif // BUTTONSTACK_H
#include "buttonstack.h" #include "ui_buttonstack.h" ButtonStack::ButtonStack(QWidget *parent) : QWidget(parent),total_buttons(0), ui(new Ui::ButtonStack) { ui->setupUi(this); } ButtonStack::~ButtonStack() { delete ui; } void ButtonStack::on_addButton_clicked() { Button* button(new Button(total_buttons++)); ui->qvboxlayout->insertWidget(0,button); connect(button,SIGNAL(remove(Button*)),this,SLOT(remove(Button*))); } void ButtonStack::remove(Button* button) { ui->qvboxlayout->removeWidget(button); delete button; }
And the main is here:
#include <QtGui/QApplication> #include "buttonstack.h" int main(int argc, char** argv) { QApplication app (argc, argv); ButtonStack bs; bs.show(); return app.exec(); }
-
Hi @apalomer ,
Have you tried to call the same slot in both cases?
Would you like to try to call a reference instead that a pointer?
Thanks
-
Hi,
So you are right clicking on the button to get the menu ? So you are likely sending the signal twice.
-
Hi,
thank you for your replies.@Charlie_Hdz I have tried what you suggest. I've changed my custom widget so that in both cases (the button click and the action triggered) the same slot is called. This is how the new custom widget looks like:
#ifndef BUTTON_H #define BUTTON_H #include <QWidget> namespace Ui { class Button; } class Button : public QWidget { Q_OBJECT public: explicit Button(int n, QWidget *parent = 0); ~Button(); private slots: void removeRequested(); signals: void remove(Button* button); private: Ui::Button *ui; }; #endif // BUTTON_H
#include "button.h" #include "ui_button.h" Button::Button(int n, QWidget *parent) : QWidget(parent), ui(new Ui::Button) { ui->setupUi(this); ui->pushButton->setText("Remove button "+QString::number(n)); addAction(ui->actionRemove); connect(ui->actionRemove,SIGNAL(triggered()),this,SLOT(removeRequested())); connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(removeRequested())); } Button::~Button() { delete ui; } void Button::removeRequested() { emit remove(this); }
The same thing happens.
@SGaist I have also tried (with this new code) what happens if I right click the button when it does not have a context menu. The Slot is not called at any time, so I think the problem does not come from emitting twice the same signal. Instead, I believe that the problem is because in the destructor of my custom widget the line
delete ui;
actually calls again the destructor of the class. This might be because it has to destroy the context menu as well? But I am not sure if this happens because of the destruction of the context menu or not, it is just my guess.
Any new ideas on what could I do?
-
Hello,
I have found the solution. Now, instead of directly deleting the widget I use deleteLater() so the widget is scheduled to be destroyed when the control returns to the event loop. The final code can be found here and it looks like:Custom widget:
#ifndef BUTTON_H #define BUTTON_H #include <QWidget> namespace Ui { class Button; } class Button : public QWidget { Q_OBJECT public: explicit Button(int n, QWidget *parent = 0); ~Button(); private slots: void removeRequested(); signals: void remove(Button* button); private: Ui::Button *ui; }; #endif // BUTTON_H
#include "button.h" #include "ui_button.h" Button::Button(int n, QWidget *parent) : QWidget(parent), ui(new Ui::Button) { ui->setupUi(this); ui->pushButton->setText("Remove button "+QString::number(n)); addAction(ui->actionRemove); connect(ui->actionRemove,SIGNAL(triggered()),this,SLOT(removeRequested())); connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(removeRequested())); } Button::~Button() { delete ui; } void Button::removeRequested() { emit remove(this); }
Main gui:
#ifndef BUTTONSTACK_H #define BUTTONSTACK_H #include <QWidget> #include "button.h" namespace Ui { class ButtonStack; } class ButtonStack : public QWidget { Q_OBJECT public: explicit ButtonStack(QWidget *parent = 0); ~ButtonStack(); private slots: void on_addButton_clicked(); void remove(Button* button); private: Ui::ButtonStack *ui; int total_buttons; }; #endif // BUTTONSTACK_H
#include "buttonstack.h" #include "ui_buttonstack.h" ButtonStack::ButtonStack(QWidget *parent) : QWidget(parent),total_buttons(0), ui(new Ui::ButtonStack) { ui->setupUi(this); } ButtonStack::~ButtonStack() { delete ui; } void ButtonStack::on_addButton_clicked() { Button* button(new Button(total_buttons++)); ui->qvboxlayout->insertWidget(0,button); connect(button,SIGNAL(remove(Button*)),this,SLOT(remove(Button*))); } void ButtonStack::remove(Button* button) { ui->qvboxlayout->removeWidget(button); button->deleteLater(); }
Main:
#include <QtGui/QApplication> #include "buttonstack.h" int main(int argc, char** argv) { QApplication app (argc, argv); ButtonStack bs; bs.show(); return app.exec(); }
-
Hello,
I have found the solution. Now, instead of directly deleting the widget I use deleteLater() so the widget is scheduled to be destroyed when the control returns to the event loop. The final code can be found here and it looks like:Custom widget:
#ifndef BUTTON_H #define BUTTON_H #include <QWidget> namespace Ui { class Button; } class Button : public QWidget { Q_OBJECT public: explicit Button(int n, QWidget *parent = 0); ~Button(); private slots: void removeRequested(); signals: void remove(Button* button); private: Ui::Button *ui; }; #endif // BUTTON_H
#include "button.h" #include "ui_button.h" Button::Button(int n, QWidget *parent) : QWidget(parent), ui(new Ui::Button) { ui->setupUi(this); ui->pushButton->setText("Remove button "+QString::number(n)); addAction(ui->actionRemove); connect(ui->actionRemove,SIGNAL(triggered()),this,SLOT(removeRequested())); connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(removeRequested())); } Button::~Button() { delete ui; } void Button::removeRequested() { emit remove(this); }
Main gui:
#ifndef BUTTONSTACK_H #define BUTTONSTACK_H #include <QWidget> #include "button.h" namespace Ui { class ButtonStack; } class ButtonStack : public QWidget { Q_OBJECT public: explicit ButtonStack(QWidget *parent = 0); ~ButtonStack(); private slots: void on_addButton_clicked(); void remove(Button* button); private: Ui::ButtonStack *ui; int total_buttons; }; #endif // BUTTONSTACK_H
#include "buttonstack.h" #include "ui_buttonstack.h" ButtonStack::ButtonStack(QWidget *parent) : QWidget(parent),total_buttons(0), ui(new Ui::ButtonStack) { ui->setupUi(this); } ButtonStack::~ButtonStack() { delete ui; } void ButtonStack::on_addButton_clicked() { Button* button(new Button(total_buttons++)); ui->qvboxlayout->insertWidget(0,button); connect(button,SIGNAL(remove(Button*)),this,SLOT(remove(Button*))); } void ButtonStack::remove(Button* button) { ui->qvboxlayout->removeWidget(button); button->deleteLater(); }
Main:
#include <QtGui/QApplication> #include "buttonstack.h" int main(int argc, char** argv) { QApplication app (argc, argv); ButtonStack bs; bs.show(); return app.exec(); }
@apalomer Congratulations.