Pregunta

Intento eliminar los widgets de una fila especificada en un QGridLayout como esto:

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

Pero cuando lo llamo, la aplicación se bloquea con SigseGV On delete item en la primera iteración. ¿Algunas ideas?

¿Fue útil?

Solución

Respuesta corta: use el código proporcionado a continuación

Eliminar una fila o columna (o incluso una sola celda) de un QGridLayout es complicado. Use el código proporcionado a continuación.

Respuesta larga: cavar en detalles de QgridLayout

Primero, tenga en cuenta que QGridLayout::rowCount() y QGridLayout::columnCount() siempre devuelva el número de asignado internamente Filas y columnas en el diseño de la cuadrícula. Como ejemplo, si llamas QGridLayout::addWidget(widget,5,7) En un diseño de cuadrícula recién construido, el recuento de filas será 6 y el recuento de columnas será 8, y todas las celdas del diseño de la cuadrícula, excepto la celda en el índice (5,7), estarán vacías y, por lo tanto, invisibles dentro de la GUI.

Tenga en cuenta que es desafortunadamente imposible Para eliminar dicha fila o columna interna del diseño de la cuadrícula. En otras palabras, el recuento de filas y columnas de un diseño de cuadrícula siempre puede crecer, pero nunca se encoge.

Lo que tu pueden hacer es eliminar el contenido de una fila o columna, que efectivamente tendrá el mismo efecto visual que eliminar la fila o columna misma. Pero esto, por supuesto, significa que todos los recuentos e índices de fila y columna permanece inalterable.

Entonces, ¿cómo se puede borrar el contenido de una fila o columna (o celda)? Desafortunadamente, esto tampoco es tan fácil como podría parecer.

Primero, debe pensar si solo desea eliminar los widgets del diseño, o si también quieres que eliminarse. Si solo elimina los widgets del diseño, debe volver a colocarlos en un diseño diferente o darles manualmente una geometría razonable. Si los widgets también se eliminan, desaparecerán de la GUI. El código proporcionado utiliza un parámetro booleano para controlar la eliminación de widgets.

A continuación, debe considerar que una celda de diseño no solo puede contener un widget, sino también un diseño anidado, que puede contener diseños anidados, y así sucesivamente. Además, necesita manejar elementos de diseño que se extienden múltiples filas y columnas. Y, finalmente, hay una fila y columna atributos como anchos y alturas mínimos que no dependen del contenido real, pero aún tienen que ser atendidos.

El código

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

Otros consejos

los QGridLayout en sí mismo está administrando el QLayoutItem's. Creo en el momento en que llamas removeWidget El artículo será eliminado. Por lo tanto, tienes un puntero inválido en ese punto. Intentando hacer cualquier cosa con él, no solo delete, fallará.

Por lo tanto, no lo elimine, estarás bien.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top