pyqt: update QGridLayout correctly when deleting all items and adding new

2.5k views Asked by At

I have a QGridLayout with 3 columns, created like this

self.my_grid = QGridLayout()
self.my_grid.setColumnStretch(2, 0)

After filling the grid with 10 items, it looks as expected like this:

X X X
X X X
X X X
X

At certain events the grid items change and I try to erase all items and add the new ones:

def updateGrid(self, taskList):

    # delete existing items from grid
    for i in reversed(range(self.my_grid.count())):
        widgetToRemove = self.my_grid.itemAt(i).widget()
        widgetToRemove.setParent(None)
        widgetToRemove.deleteLater()

    # add new buttons
    for task in tasklist:
        btn = QPushButton(task)
        self.my_grid.addWidget(btn)

But then it shows with an empty cell like this:

  X X
X X X
X X X
X X

And after calling updateGrid again, it has two empty cells like this:

    X
X X X
X X X
X X X

And finally, after forcing one more update again I get what I expected:

X X X
X X X
X X X
X

How can I avoid the empty cells?

1

There are 1 answers

2
ekhumoro On BEST ANSWER

The QGridLayout and QFormLayout classes do not delete their rows when widgets are removed. The empty rows don't take up any vertical space, but if you add widgets without specifying a row and column, they will be placed next to the last empty column. There is no way to reset the number of rows and/or columns back to zero in these layouts.

In your example, the last row has a one item in column zero. So on the next iteration, the first widget will be added at column one. Then on the next iteration, the last row will have two items, so the first widget will be placed at column two - and so forth, until you get back to where you started.

To fix this, you can re-use the existing empty rows and columns, and update the grid something like this:

def updateGrid(self, taskList):
    for i in reversed(range(self.my_grid.count())):
        widgetToRemove = self.my_grid.itemAt(i).widget()
        widgetToRemove.setParent(None)
        widgetToRemove.deleteLater()
    try:
        index = 0
        for row in range(self.my_grid.rowCount()):
            for column in range(self.my_grid.columnCount()):
                btn = QPushButton(taskList[index])
                self.my_grid.addWidget(btn, row, column)
                index += 1
    except IndexError:
        pass