Ответ 1
Краткий ответ: используйте код, указанный ниже
Удалить строку или столбец (или даже одну ячейку) из QGridLayout
сложно. Используйте код, указанный ниже.
Длинный ответ: копание в деталях QGridLayout
Во-первых, обратите внимание, что QGridLayout::rowCount()
и QGridLayout::columnCount()
всегда возвращают количество внутренних строк и столбцов в макете сетки. Например, если вы QGridLayout::addWidget(widget,5,7)
в только что построенном макете сетки, то число строк будет равно 6, а количество столбцов будет равно 8, и все ячейки макета сетки, кроме ячейки на Индекс (5,7) будет пустым и, следовательно, невидимым в GUI.
Обратите внимание, что, к сожалению, невозможно удалить такую внутреннюю строку или столбец из компоновки сетки. Другими словами, количество строк и столбцов макета сетки всегда может только расти, но никогда не уменьшаться.
Что вы можете сделать, так это удалить содержимое строки или столбца, что будет иметь тот же визуальный эффект, что и удаление самой строки или столбца. Но это, конечно, означает, что все количество строк и столбцов и индексы останутся неизменными.
Так как же очистить содержимое строки или столбца (или ячейки)? К сожалению, это не так просто, как может показаться.
Во-первых, вам нужно подумать, хотите ли вы только удалить виджеты из макета или же вы хотите, чтобы они стали удалены. Если вы удаляете только виджеты из макета, вы должны впоследствии вернуть их в другой макет или вручную придать им разумную геометрию. Если виджеты также будут удалены, они исчезнут из графического интерфейса. Предоставленный код использует логический параметр для управления удалением виджета.
Далее необходимо учитывать, что ячейка макета может содержать не только виджет, но и вложенный макет, который сам может содержать вложенные макеты и т.д. Кроме того, вам нужно обрабатывать элементы макета, которые охватывают несколько строк и столбцов. И, наконец, есть некоторые атрибуты строк и столбцов, такие как минимальная ширина и высота, которые не зависят от фактического содержимого, но о которых нужно позаботиться.
Код
#include <QGridLayout>
#include <QWidget>
/**
* Utility class to remove the contents of a QGridLayout row, column or
* cell. If the deleteWidgets parameter is true, then the widgets become
* not only removed from the layout, but also deleted. Note that we won't
* actually remove any row or column itself from the layout, as this isn't
* possible. So the rowCount() and columnCount() will always stay the same,
* but the contents of the row, column or cell will be removed.
*/
class GridLayoutUtil {
public:
// Removes the contents of the given layout row.
static void removeRow(QGridLayout *layout, int row, bool deleteWidgets = true) {
remove(layout, row, -1, deleteWidgets);
layout->setRowMinimumHeight(row, 0);
layout->setRowStretch(row, 0);
}
// Removes the contents of the given layout column.
static void removeColumn(QGridLayout *layout, int column, bool deleteWidgets = true) {
remove(layout, -1, column, deleteWidgets);
layout->setColumnMinimumWidth(column, 0);
layout->setColumnStretch(column, 0);
}
// Removes the contents of the given layout cell.
static void removeCell(QGridLayout *layout, int row, int column, bool deleteWidgets = true) {
remove(layout, row, column, deleteWidgets);
}
private:
// Removes all layout items which span the given row and column.
static void remove(QGridLayout *layout, int row, int column, bool deleteWidgets) {
// We avoid usage of QGridLayout::itemAtPosition() here to improve performance.
for (int i = layout->count() - 1; i >= 0; i--) {
int r, c, rs, cs;
layout->getItemPosition(i, &r, &c, &rs, &cs);
if (
(row == -1 || (r <= row && r + rs > row)) &&
(column == -1 || (c <= column && c + cs > column))) {
// This layout item is subject to deletion.
QLayoutItem *item = layout->takeAt(i);
if (deleteWidgets) {
deleteChildWidgets(item);
}
delete item;
}
}
}
// Deletes all child widgets of the given layout item.
static void deleteChildWidgets(QLayoutItem *item) {
QLayout *layout = item->layout();
if (layout) {
// Process all child items recursively.
int itemCount = layout->count();
for (int i = 0; i < itemCount; i++) {
deleteChildWidgets(layout->itemAt(i));
}
}
delete item->widget();
}
};