2

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?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
user3729611
  • 385
  • 3
  • 9

1 Answers1

5

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
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • Ahh thanks a lot for this. Excellent answer. Since the number of items in the grid will change for each reload of items, I cannot reuse the existing rows, but I guess I will have to replace the complete grid. – user3729611 Sep 13 '17 at 07:36
  • @user3729611. If the number of *rows* changes, but the number of columns stays the same, then my answer will still work. With some small changes, it should also be possible to change the number of columns. The grid just automatically grows in either dimension. – ekhumoro Sep 13 '17 at 11:16