1

I'm trying to build a QGridLayout with stretchable-width columns but non-stretchable-height rows. The grid in inside a QScrollArea, and with the exception of the height, it's almost working. You can see it in the following images:

enter image description here

enter image description here

As you can see, the rows are being vertically stretched. I would like all the rows to be equal and to not fit all the parent's height if there are too few rows (first image). Should I touch the grid or the actual widgets?

Edit: reproducible example

import sys
from PyQt5.QtWidgets import (QWidget, QGridLayout, QLabel, QRadioButton, QApplication, QScrollArea, QVBoxLayout)

class ScrollableGrid(QWidget):

    def __init__(self, columnSpans, minimumColumnWidth):

        super().__init__()

        # Grid
        self.grid = QWidget()
        self.gridLayout = QGridLayout()

        for i in range(len(columnSpans)):
            self.gridLayout.setColumnStretch(i, columnSpans[i])
            self.gridLayout.setColumnMinimumWidth(i, columnSpans[i] * minimumColumnWidth)

        self.grid.setLayout(self.gridLayout)

        # Scroll area
        self.scrollArea = QScrollArea()
        self.scrollArea.setWidget(self.grid)
        self.scrollArea.setWidgetResizable(True)

        # Compute the correct minimum width
        width = (self.grid.sizeHint().width() +
                 self.scrollArea.verticalScrollBar().sizeHint().width() +
                 self.scrollArea.frameWidth() * 2)

        self.scrollArea.setMinimumWidth(width)

        # Layout
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.scrollArea)
        self.setLayout(self.layout)


    def addRow(self, row, elements):
        for column in range(len(elements)):
            self.gridLayout.addWidget(elements[column], row, column)


class MainWindow(QWidget):

    def __init__(self):

        super().__init__()

        # ScrollableGrid
        self.grid = ScrollableGrid(columnSpans=[1,2,3], minimumColumnWidth=100)

        # Add rows
        for i in range(3):
            self.grid.addRow(i, [QLabel('A'), QLabel('B'), QRadioButton()])

        # Window layout
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.grid)
        self.setLayout(self.layout)


if __name__ == '__main__':

    app = QApplication(sys.argv)
    windowExample = MainWindow()
    windowExample.show()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
dvilela
  • 1,200
  • 12
  • 29
  • 1
    please provide a [mcve] – S. Nick Jun 10 '20 at 17:31
  • @S.Nick Done, thank you. – dvilela Jun 10 '20 at 17:42
  • 1
    Try adding the line `self.grid.gridLayout.setRowStretch (111, 1)` before the line `# Window layout` – S. Nick Jun 10 '20 at 18:38
  • Sorry for the delay @S.Nick and thank you for your help. It works nicely. Despite I am reading the online docs for setRowStretch, I don't get how it works. Those arguments are (int row, int stretch). So why does passing a 111 to row work? What does the 111,1 mean? And why should it be called in that specific place? Is it because it must me called after all rows have been added? If you like, you can post your previous answer as an answer and not a comment so I can select it. – dvilela Jun 12 '20 at 10:47

1 Answers1

1

void QGridLayout::setRowStretch(int row, int stretch)

Sets the stretch factor of row row to stretch. The first row is number 0.

The stretch factor is relative to the other rows in this grid. Rows with a higher stretch factor take more of the available space.

Yes, is it because it must me called after all rows have been added.

import sys
from PyQt5.QtWidgets import (QWidget, QGridLayout, QLabel, QRadioButton, 
                             QApplication, QScrollArea, QVBoxLayout)

class ScrollableGrid(QWidget):
    def __init__(self, columnSpans, minimumColumnWidth):
        super().__init__()

        # Grid
        self.grid = QWidget()
        self.gridLayout = QGridLayout()

        for i in range(len(columnSpans)):
            self.gridLayout.setColumnStretch(i, columnSpans[i])
            self.gridLayout.setColumnMinimumWidth(i, columnSpans[i] * minimumColumnWidth)
        self.grid.setLayout(self.gridLayout)

        # Scroll area
        self.scrollArea = QScrollArea()
        self.scrollArea.setWidget(self.grid)
        self.scrollArea.setWidgetResizable(True)

        # Compute the correct minimum width
        width = (self.grid.sizeHint().width() +
                 self.scrollArea.verticalScrollBar().sizeHint().width() +
                 self.scrollArea.frameWidth() * 2)
        self.scrollArea.setMinimumWidth(width)

        # Layout
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.scrollArea)
        self.setLayout(self.layout)

    def addRow(self, row, elements):
        for column in range(len(elements)):
            self.gridLayout.addWidget(elements[column], row, column)
        

class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        # ScrollableGrid
        self.grid = ScrollableGrid(columnSpans=[1,2,3], minimumColumnWidth=100)

        # Add rows
        for i in range(3):
            self.grid.addRow(i, [QLabel('A'), QLabel('B'), QRadioButton()])
            
        self.grid.gridLayout.setRowStretch(111, 1)                                # !!!

        # Window layout
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.grid)
        self.setLayout(self.layout)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    windowExample = MainWindow()
    windowExample.show()
    sys.exit(app.exec_())

enter image description here

Community
  • 1
  • 1
S. Nick
  • 12,879
  • 8
  • 25
  • 33