14

次のように、指定された行からウィジェットを削除しようとします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 をオンにしてクラッシュします。何か案は?

4

2 に答える 2

31

簡単な答え: 以下のコードを使用してください

から行または列 (または 1 つのセル) を削除するのQGridLayoutは注意が必要です。以下に示すコードを使用します。

長い答え: QGridLayout の詳細を掘り下げる

QGridLayout::rowCount()まず、とは常に、グリッド レイアウトで内部的に割り当てられた行と列QGridLayout::columnCount()の数を返すことに注意してください。例として、新たに構築されたグリッド レイアウトを呼び出す場合、行数は 6、列数は 8 になり、インデックス (5,7) のセルを除くグリッド レイアウトのすべてのセルは空になるため、 GUI 内では見えません。QGridLayout::addWidget(widget,5,7)

残念ながら、そのような内部の行または列をグリッド レイアウトから削除することはできないことに注意してください。つまり、グリッド レイアウトの行数と列数は常に増加するだけで、減少することはありません。

できることは、行または列の内容を削除することです。これにより、行または列自体を削除するのと同じ視覚効果が効果的に得られます。しかしもちろん、これはすべての行と列の数とインデックスが変更されないままであることを意味します。

では、行または列 (またはセル) の内容をクリアするにはどうすればよいでしょうか? 残念ながら、これも思ったほど簡単ではありません。

まず、レイアウトからウィジェットを削除するだけなのか、それともウィジェットも削除したいのかを考える必要があります。ウィジェットをレイアウトから削除するだけの場合は、後で別のレイアウトに戻すか、手動で妥当なジオメトリを与える必要があります。ウィジェットも削除されると、GUI から消えます。提供されたコードは、boolean パラメーターを使用してウィジェットの削除を制御します。

次に、レイアウト セルにはウィジェットだけでなく、ネストされたレイアウトを含むことができるネストされたレイアウトなども含まれることを考慮する必要があります。さらに、複数の行と列にまたがるレイアウト アイテムを処理する必要があります。そして最後に、実際の内容に依存しない最小の幅と高さのような、いくつかの行と列の属性がありますが、それでも注意が必要です。

コード

#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();
  }
};
于 2013-10-08T19:49:59.073 に答える
3

QGridLayout自身が を管理していますQLayoutItem。あなたが電話をかけた瞬間removeWidgetにアイテムは削除されると思います。したがって、その時点で無効なポインターがあります。だけでなく、何かをしようとするdeleteと失敗します。

したがって、削除しないでください。問題ありません。

于 2011-03-22T17:24:25.507 に答える