I am trying to make a widget with an adaptive grid layout - I calculate optimal number of columns for a given widget size and fill the QGridLayout accordingly.
When an item is added or the size of the widget changes (on ResizeEvent
) the following function is called:
void AdaptiveGrid::updateGrid() {
const auto maxCols = calculateOptimalCols();
// empty the layout, but don't delete the widgets
while (auto* item = layout_->takeAt(0)) {}
auto currentRow = 0;
auto currentCol = 0;
for (auto* widget : widgets_) {
layout_->addWidget(widget, currentRow, currentCol);
++currentCol;
if (currentCol == maxCols) {
++currentRow;
currentCol = 0;
}
}
}
Then, when using this widget, I add a few expanding widgets to it and see the following behavior: when a new element is added and layout takes ownership of the element the size happens to be whatever it was by default and the element pushes all other grid items off. Then, when I start resizing the window, the sizes of items get normalized to be the same (but not instantly, it seems like every ResizeEvent nudges items' sizes closer to the correct one).
If I understand correctly, by default stretches should be 1 for all items in a layout and on update, such as adding new item, layout should iteratively recalculate all sizes according to the constraints. Why doesn't it happen instantly and instead in this strange deferred way?
Ok, I was wrong about the default stretches, it seems they default to 0, and my expanding widgets have to duke it out until settling on stable sizes. Solved it by setting all stretch factors to 1, and removing them on update to avoid possible empty cells after items removal or row number change:
void AdaptiveGrid::updateGrid() {
const auto maxCols = calculateOptimalCols();
for (auto row = 0; row < layout_->rowCount(); ++row) {
layout_->setRowStretch(row, 0);
}
for (auto col = 0; col < layout_->columnCount(); ++col) {
layout_->setColumnStretch(col, 0);
}
// empty the layout, but don't delete the widgets
while (auto* item = layout_->takeAt(0)) {}
auto currentRow = 0;
auto currentCol = 0;
for (auto* widget : widgets_) {
layout_->addWidget(widget, currentRow, currentCol);
layout_->setRowStretch(currentRow, 1);
layout_->setColumnStretch(currentCol, 1);
++currentCol;
if (currentCol == maxCols) {
++currentRow;
currentCol = 0;
}
}
}