Mike
Mike

Reputation: 13

PyQt5 calling qwidget.setMaximumHeight causes content to disappear

The code below runs as I expect it to. It creates a very long page that runs off the screen filled with widgets. What I would like to achieve is the same page but shorter with a scrollbar. Seems easy enough. The commented line: self.topWidget.setMaximumHeight(500) achieves the size when I uncomment it but all the content disappears. Why does that line produces that result and how do I fix it? A better alternate approach would also be interesting. Thanks!

import sys
from PyQt5.QtWidgets import (QWidget, QLabel, QApplication, QCheckBox, QHBoxLayout,
                             QVBoxLayout, QGridLayout)
class Example(QWidget):

    def __init__(self, labels):
        super().__init__()
        self.labels = labels

        self.topWidget = QWidget()
        self.vbox = QVBoxLayout()
        self.topWidget.setLayout(self.vbox)

        self.topgrid = QGridLayout()
        self.topgrid.addWidget(self.topWidget)
        self.setLayout(self.topgrid)

        self.initUI()
        self.show()

    def initUI(self):

        for i, t in enumerate(self.labels):
            widget = QWidget()
            widget.setMaximumHeight(40)
            hlayout = QHBoxLayout()
            lab = QLabel(t)
            lab.setMinimumWidth(self.maxWidth(self.labels) * 6 + 30)

            hlayout.addWidget(lab)
            hlayout.addWidget(QCheckBox("activate"))
            widget.setLayout(hlayout)
            self.vbox.addWidget(widget)

        # self.topWidget.setMaximumHeight(500)

        self.setWindowTitle('Dynamic layout')

    def maxWidth(self, arr):
        mWidth = 0
        for a in arr:
            mWidth = max(len(a), mWidth)
        return mWidth


if __name__ == '__main__':
    app = QApplication(sys.argv)
    labs = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',]
    ex = Example(labs)
    sys.exit(app.exec_())

Upvotes: 1

Views: 298

Answers (2)

eyllanesc
eyllanesc

Reputation: 243897

Explanation:

To better understand the phenomenon, the maximumHeight must be varied, for example with 2800 the following is obtained:

enter image description here

As you can see, each widget has the same height since the widgets are similar and the QVBoxLayout will set the same height for each element, and if that height is less than necessary, then only a part will be shown. If a calculation is made with maximumHeight of 500 for the 90 widgets with a spacing of 6 pixels, then it is obtained (500 - (89 + 1 + 1) * 6) / 90 = -0.5 that is equivalent to 0, and therefore does not widgets are observed.

Solution:

Even when the widgets are displayed then a scrollbar does not appear magically. The solution is to use a QScrollArea that implements that functionality.

class Example(QWidget):
    def __init__(self, labels):
        super().__init__()
        self.labels = labels

        self.topWidget = QScrollArea(widgetResizable=True)

        self.topgrid = QGridLayout(self)
        self.topgrid.addWidget(self.topWidget)

        self.initUI()
        self.show()

    def initUI(self):

        content_widget = QWidget()
        vbox = QVBoxLayout(content_widget)
        self.topWidget.setWidget(content_widget)

        for i, t in enumerate(self.labels):
            widget = QWidget()
            hlayout = QHBoxLayout(widget)

            lab = QLabel(t)
            hlayout.addWidget(lab)
            hlayout.addWidget(QCheckBox("activate"))

            vbox.addWidget(widget)

        self.setWindowTitle("Dynamic layout")

enter image description here

Upvotes: 2

Paul
Paul

Reputation: 274

I slightly reworked your code so you can make it scrollable.

import sys
from PyQt5.QtWidgets import (QWidget, QLabel, QApplication, QCheckBox, QHBoxLayout,
                             QVBoxLayout, QGroupBox, QGridLayout, QFormLayout, QScrollArea)
from PyQt5.QtCore import Qt, pyqtSignal, QSize, QRect
class Example(QWidget):

    def __init__(self, labels):
        super().__init__()
        self.labels = labels

        self.topWidget = QWidget()
        self.vbox = QVBoxLayout()
        self.topWidget.setLayout(self.vbox)

        self.topgrid = QGridLayout()
        self.topgrid.addWidget(self.topWidget)
        self.setLayout(self.topgrid)

        self.initUI()
        self.show()

    def initUI(self):
        groupBox = QGroupBox("This Is Group Box")
        label_list = []
        checkbox_list = []
        formLayout =QFormLayout()
        for i, t in enumerate(self.labels):
            lab = QLabel(t)
            lab.setMinimumWidth(self.maxWidth(self.labels) * 6 + 30)

            label_list.append(lab)
            checkbox_list.append(QCheckBox("activate"))
            formLayout.addRow(label_list[i], checkbox_list[i])

        groupBox.setLayout(formLayout)
        scroll = QScrollArea()
        scroll.setWidget(groupBox)
        scroll.setWidgetResizable(True)
        scroll.setFixedHeight(400)
        self.vbox.addWidget(scroll)
        self.show()

        self.setWindowTitle('Dynamic layout')

    def maxWidth(self, arr):
        mWidth = 0
        for a in arr:
            mWidth = max(len(a), mWidth)
        return mWidth


if __name__ == '__main__':
    app = QApplication(sys.argv)
    labs = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',]
    ex = Example(labs)
    sys.exit(app.exec_())



Upvotes: 0

Related Questions