繁体   English   中英

从QGridLayout中删除小部件

[英]Removing widgets from QGridLayout

我尝试从QGridLayout的指定行中删除小部件,如下所示:

void delete_grid_row(QGridLayout *layout, int row)
{
    if (!layout || row < 0) return;

    for (int i = 0; i < layout->columnCount(); ++i) {
        QLayoutItem* item = layout->itemAtPosition(row, i);
        if (!item) continue;

        if (item->widget()) {
            layout->removeWidget(item->widget());
        } else {
            layout->removeItem(item);
        }
        delete item;
    }
}

但是当我调用它时,应用程序在第一次迭代中与delete item上的SIGSEGV崩溃。 有任何想法吗?

简答:使用下面提供的代码

QGridLayout删除行或列(甚至单个单元格)非常棘手。 使用下面提供的代码。

答案很长:深入研究QGridLayout细节

首先,请注意QGridLayout::rowCount()QGridLayout::columnCount()始终返回网格布局中内部分配的行和列的数量。 例如,如果在新构造的网格布局上调用QGridLayout::addWidget(widget,5,7) ,行计数将为6,列计数将为8,并且网格布局的所有单元格除了单元格之外index(5,7)将为空,因此在GUI中不可见。

请注意,遗憾的无法从网格布局中删除此类内部行或列。 换句话说,网格布局的行数和列数始终只会增长,但永远不会缩小。

可以做的是删除行或列的内容 ,这将有效地具有与删除行或列本身相同的视觉效果。 但这当然意味着所有行和列计数和索引将保持不变

那么如何清除行或列(或单元格)的内容呢? 遗憾的是,这并不像看起来那么容易。

首先,您需要考虑是否只想从布局中删除小部件,或者是否还希望它们被删除 如果只从布局中删除小部件,则必须在之后将它们放回到不同的布局中,或者手动为它们提供合理的几何图形。 如果窗口小部件也被删除,它们将从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();
  }
};

QGridLayout本身正在管理QLayoutItem 我相信你调用removeWidget的那一刻该项目将被删除。 因此,您在该点有一个无效指针。 试图用它做任何事情,而不仅仅是delete ,都会失败。

因此,只是不删除它,你会没事的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM