Reputation: 79
In QT, how to remove child widget from parent after receiving the signal generated by child?
I am using QT 5.7 and write a simple program with 2 widget, view1 and view2. There is a button named "btn_1" inside view1, and a button named "btn_leave" inside view2.
When you click "btn_1", it will generate a view2 object and add it into layout of view1. I want view2 be deleted when clicking "btn_leave".
Here is my thought. When clicking leave_btn in view2, it emits a signal called "leave". And I connect this signal to a lambda function in order to delete view2.
void VIEW1::on_btn_1_clicked() {
VIEW2 *view2 = new VIEW2();
layout->addWidget(view2);
connect(view2, &VIEW2::leave, this, [&view2]() {
delete view2;
});
}
The program goes crashed not surprisingly, because I delete view2 while signal is emitting from view2. view2 may access its member after emitting leave signal.
So I rewrite it with deleteLater. According to QT document, the object will be deleted when control returns to the event loop.
void VIEW1::on_btn_1_clicked() {
VIEW2 *view2 = new VIEW2();
layout->addWidget(view2);
connect(view2, &VIEW2::leave, this, [&view2]() {
view2.deleteLater();
});
}
But surprisingly, the program goes crashed again. Is there anything I misunderstand about the usage of deleteLater or there are still some event inside event queue access view2 after calling deletelater()?
I have uploaded my whole program(created with QT creator) to github if that helps.
Upvotes: 1
Views: 1128
Reputation: 243983
You have to pass the pointer of view2
, not the pointer of the pointer, besides this
it is not necessary.
void VIEW1::on_btn_1_clicked() {
VIEW2 *view2 = new VIEW2();
layout->addWidget(view2);
connect(view2, &VIEW2::leave, [view2]() {
view2->deleteLater();
});
}
Or simply do not use a lambda function, but the new connection style:
void VIEW1::on_btn_1_clicked() {
VIEW2 *view2 = new VIEW2();
layout->addWidget(view2);
connect(view2, &VIEW2::leave, view2, &VIEW2::deleteLater);
}
Another option is not to create the leave
signal, and make the connection of the clicked signal
VIEW2::VIEW2(QWidget *parent) :
QWidget(parent)
{
label = new QLabel(this);
label->setText("view2");
btn_leave = new QPushButton(this);
btn_leave->setText("leave");
layout = new QHBoxLayout;
layout->addWidget(label);
layout->addWidget(btn_leave);
setLayout(layout);
connect(btn_leave, &QAbstractButton::clicked, this, &VIEW2::deleteLater);
}
Upvotes: 4