This question is an exact duplicate of:
I am using Qt5 (beginner) on Windows7.
In the main window of my app I want to display and remove some push-buttons.
widget = new ButtonWidget(ui->frame); // frame is a QScrollArea
connect(ui->addBtns, SIGNAL(clicked()), widget, SLOT(addButtons()));
connect(ui->deleteBtns, SIGNAL(clicked()), widget, SLOT(deleteButtons()));
And the ButtonWidget
class is here:
ButtonWidget::ButtonWidget(QWidget * parent) : QWidget(parent)
{
//addButtons();
}
void ButtonWidget::addButtons()
{
QStringList texts{"1\nok", "2\nok", "3\nok", "4\nok", "5\nok", "6\nok"};
gridLayout = new QGridLayout;
for(int i = 0; i < texts.size(); i++)
{
QPushButton * button = new QPushButton(texts[i]);
gridLayout->addWidget(button, i / 5, i % 5);
}
setLayout(gridLayout);
}
// I'm not sure this method/function is ok... :(
void ButtonWidget::deleteButtons()
{
QLayoutItem * child;
while((child = gridLayout->takeAt(0)) != 0)
{
gridLayout->removeWidget(child->widget());
delete child->widget();
delete child;
}
delete gridLayout;
}
Problem is: when I click on add_buttons
, I get all buttons displayed, but they are shrunk, tiny or something... :
OTOH... if I remove the comment from addButtons()
call in the constructor (hence calling from within the constructor), the result is ok:
So, finally I have 2 questions:
1) How to fix the code to be able to add those buttons properly (when add_buttons
is clicked)?
2) Is the deleteButtons()
method ok?
First, I would recommend to do
in the constructor. You don't need to delete all the grid, create it again and set in as a layout when you can just remove its content (with delete button for example) and fill it again afterwards.
EDIT : comment of Werner Erasmus : No need to set the layout. The fact that it has a parent widget implies that it sets itself up.
The problem is that is you do not modify addButtons() you will substitute the previous buttons without knowing where they go.
Also, try to give the QPushButton a parent :
For your second point : Removing widgets from QGridLayout
EDIT:
After some more testing (without looking at the source code, but suspecting that it must be safe to delete button, else things would be brittle), I've implemented removeButtons as follows:
This works, and it proves that deleting a widget also removes the widget from it's parent, and layouts associated with the parent (by slots hooked up to when a child widget is deleted). The above code confirms this, as count(), which refers to number of layout items, decrease to zero (and those layout items are managed by the Layout). takeAt(x) is never called, and doesn't need to be - simply delete the widgets (buttons). Wholla!
ORIGINAL ANSWER
As mentioned in my other post, you only need to delete the buttons (it is removed from its parent automatically). However, if a widget was added to a layout, the parent of that layout becomes the parent of the widget, and an associated QLayoutItem is created that is managed by the layout itself. To the delete the buttons, the safest way is to take all the layout items (ownership the taker's responsibility), delete each items associated widget, and the delete each item. I'll try and find relevant references apart from the sources...
The following code works:
You need to enable c++11 in your config (.pro) to get the lambdas working.
I've used QHBoxLayout for your buttons, as it better models what you want. Although strictly not necessary, I'm returning unique_ptr from the makeArea in main, as it has not parent, I'm not sure whether it gets some parent because it is the first widget created, but unique_ptr shows intent.
NOTE:
Apparently the layout item is not the parent of the widget, but the widget associated with the layout itself is the parent of widgets belonging to its layout item.