Skip to content
Advertisement

QGridlLayout with non-stretchable-height rows

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_())

Advertisement

Answer

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

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement