Domanda

Cerco di rimuovere i widget da una riga specificata in a QGridLayout come questo:

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;
    }
}

Ma quando lo chiamo, l'app si blocca con Sigsegv delete item Nella prima iterazione. Qualche idea?

È stato utile?

Soluzione

Risposta breve: utilizzare il codice fornito di seguito

Rimuovere una riga o una colonna (o anche una singola cella) da a QGridLayout è complicato. Utilizzare il codice fornito di seguito.

Risposta lunga: scavare nei dettagli di qgridlayout

Innanzitutto, nota che QGridLayout::rowCount() e QGridLayout::columnCount() restituire sempre il numero di allocato internamente righe e colonne nel layout della griglia. Ad esempio, se chiami QGridLayout::addWidget(widget,5,7) Su un layout della griglia appena costruito, il numero di righe sarà 6 e il conteggio delle colonne sarà 8 e tutte le celle del layout della griglia tranne la cella su indice (5,7) saranno vuote e quindi invisibili all'interno della GUI.

Nota che purtroppo è impossibile Per rimuovere tale riga o colonna interna dal layout della griglia. In altre parole, il conteggio della riga e delle colonne di un layout della griglia non può sempre crescere, ma non ridursi mai.

Cosa tu Potere fare è rimuovere il file Contenuti di una riga o colonna, che avrà effettivamente lo stesso effetto visivo della rimozione della riga o della colonna stessa. Ma questo ovviamente significa che tutti i conteggi e gli indici della riga e delle colonne lo faranno rimane invariato.

Quindi, come si può cancellare il contenuto di una riga o colonna (o cella)? Anche questo non è così facile come potrebbe sembrare.

Innanzitutto, devi pensare se vuoi solo rimuovere i widget dal layout, o se vuoi anche loro diventare eliminato. Se rimuovi solo i widget dal layout, è necessario riportarli in un layout diverso in seguito o dare loro una geometria ragionevole. Se anche i widget vengono eliminati, scompariranno dalla GUI. Il codice fornito utilizza un parametro booleano per controllare la cancellazione del widget.

Successivamente, devi considerare che una cella di layout non può solo contenere solo un widget, ma anche a layout nidificato, che a sua volta può contenere layout nidificati e così via. È inoltre necessario gestire oggetti di layout che si estendono più righe e colonne. E, infine, ci sono una riga e una colonna attributi Come larghezze minime e altezze che non dipendono dai contenuti effettivi ma devono comunque essere curati.

Il codice

#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();
  }
};

Altri suggerimenti

Il QGridLayout stesso sta gestendo il QLayoutItem'S. Credo nel momento in cui chiami removeWidget L'articolo verrà eliminato. Quindi hai un puntatore non valido a quel punto. Tentare di fare qualsiasi cosa con esso, non solo delete, avrà esito negativo.

Quindi, semplicemente non eliminarlo, starai bene.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top