1

I have the problem that completely drives me mad.

I am writing GUI application on Python using PyQt5. My application consists of multiple QGroupBoxes, that become visible and non-visible as user switches between them.

One of QGroupBoxes contains QScrollArea, in which another QGroupBoxes are placed. As user adds information to application, new QGroupBoxes might be added, so QScrollArea should allow to view all of them when there are too much elements added.

So the structure of elements is:

QGroupBox
=>QScrollArea
=>=>QScrollAreaWidgetContents
=>=>=>QVBoxLayout
=>=>=>=>QGroupBox
=>=>=>=>=>QFormLayout
=>=>=>=>QGroupBox
=>=>=>=>=>QFormLayout

However, even though I placed inner QGroupBoxes inside a vertical layout and then inside a single QScrollAreaWidgetContents, QScrollArea does not show any scrollbars, but instead resizes inner elements, so it looks like this.

My problem can be summed up in this example:

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(415, 213)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox.setGeometry(QtCore.QRect(0, 0, 801, 601))
        self.groupBox.setObjectName("groupBox")
        self.scrollArea = QtWidgets.QScrollArea(self.groupBox)
        self.scrollArea.move(10, 30)
        self.scrollArea.setFixedWidth(380)
        self.scrollArea.setMinimumHeight(160)
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setObjectName("scrollArea")
        self.scrollAreaWidgetContents = QtWidgets.QWidget()
        self.scrollAreaWidgetContents.move(0, 0)
        self.scrollAreaWidgetContents.setFixedWidth(378)
        self.scrollAreaWidgetContents.setMinimumHeight(158)
        self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
        self.scrollArea.setWidget(self.scrollAreaWidgetContents)
        MainWindow.setCentralWidget(self.centralwidget)

       QtCore.QMetaObject.connectSlotsByName(MainWindow)

class competencyBox(QWidget):
    def __init__(self, parent):
        super(competencyBox, self).__init__(parent)
        self.compCodeLineEdit = QLineEdit()
        self.compDescrpTextEdit = QTextEdit()
        self.box = QGroupBox(self)
        self.form_lay = QFormLayout(self)
        self.form_lay.addRow(QLabel("Код: "), self.compCodeLineEdit)
        self.form_lay.addRow(QLabel("Описание: "), self.compDescrpTextEdit)
        self.box.setLayout(self.form_lay)
        self.box.setFixedSize(510, 240)

class test_window(QMainWindow):
    def __init__(self):
        super(test_window, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.addBox(self.ui.scrollAreaWidgetContents, competencyBox, 4)

    def addBox(self, parent, element, number):
        vert_lay = QVBoxLayout(parent)
        for i in range(number):
            e = element(parent)
            vert_lay.addWidget(e)
        vert_lay.setSpacing(5)

As you may notice, I tried different approaches, such as setting fixed size to inner QGroupBoxes, adding spacing into the vertical layout and so on, but QScrollArea still ignores them and shrinks inner elements. I am stuck and got no idea how to solve my problem. Please help me.

Anton
  • 83
  • 1
  • 5
  • please provide a [mcve] – eyllanesc Nov 23 '18 at 19:33
  • This man had almost identical problem as me, though his solution doesn't apply to me: https://stackoverflow.com/questions/12781407/how-do-i-resize-the-contents-of-a-qscrollarea-as-more-widgets-are-placed-inside as I already have `setWidgetResizeable(True)` applied to my QScrollArea. – Anton Nov 23 '18 at 19:35
  • mmmm, what does this have to do with my request? – eyllanesc Nov 23 '18 at 19:36
  • this problem is often not caused by the QScrollArea but from another part of the OP code, so that's why I've asked you for an MCVE – eyllanesc Nov 23 '18 at 19:38
  • @eyllanesc Sorry, haven't seen your comment before sending mine. I will recreate an example asap. – Anton Nov 23 '18 at 19:40
  • 2
    I recommend that for future occasions you provide a [mcve], code to pieces is good to illustrate or explain but not for the problems: *I want X and I do Y but it does not work*, since the error may be in the hidden part of your code and we'll never know, that's why SO introduces the concept of MCVE – eyllanesc Nov 23 '18 at 19:43
  • @eyllanesc Thank you for pointing out my mistake. I added MCVE to my question. – Anton Nov 23 '18 at 20:09

1 Answers1

0

The main problem in your case is that the scrollAreaWidgetContents should not have a fixed size since it is the container of the widgets and if you use self.scrollAreaWidgetContents.setFixedWidth (378) you are setting it, the size of the scrollAreaWidgetContents should be the set size. widgets through the QVBoxLayout.

Another problem is that CompetencyBox must use a layout to set up the QGroupBox.

from PyQt5 import QtCore, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(415, 213)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox.setGeometry(QtCore.QRect(0, 0, 801, 601))
        self.groupBox.setObjectName("groupBox")
        self.scrollArea = QtWidgets.QScrollArea(self.groupBox)
        self.scrollArea.move(10, 30)
        self.scrollArea.setFixedWidth(380)
        self.scrollArea.setMinimumHeight(160)
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setObjectName("scrollArea")
        self.scrollAreaWidgetContents = QtWidgets.QWidget()
        self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
        self.scrollArea.setWidget(self.scrollAreaWidgetContents)
        MainWindow.setCentralWidget(self.centralwidget)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

class CompetencyBox(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(CompetencyBox, self).__init__(parent)
        self.compCodeLineEdit = QtWidgets.QLineEdit()
        self.compDescrpTextEdit = QtWidgets.QTextEdit()
        lay = QtWidgets.QVBoxLayout(self)
        box = QtWidgets.QGroupBox()
        lay.addWidget(box)
        form_lay = QtWidgets.QFormLayout()
        form_lay.addRow(QtWidgets.QLabel("Код: "), self.compCodeLineEdit)
        form_lay.addRow(QtWidgets.QLabel("Описание: "), self.compDescrpTextEdit)
        box.setLayout(form_lay)
        box.setFixedSize(510, 240)

class Test_Window(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(Test_Window, self).__init__(parent)
        self.setupUi(self)
        self.addBox(self.scrollAreaWidgetContents, CompetencyBox, 4)

    def addBox(self, parent, element, number):
        vert_lay = QtWidgets.QVBoxLayout(parent)
        for i in range(number):
            vert_lay.addWidget(element())
        vert_lay.setSpacing(5)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Test_Window()
    w.resize(640, 480)
    w.show()
    sys.exit(app.exec_())

enter image description here

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • However, I would like to clarify something. Why should we put QGroupBox in another one layout? It seems that I've already done this in `addBox()` method. PyQt also keeps notify me, that `QLayout: Attempting to add QLayout "" to competencyBox "", which already has a layout`. Apart from that, everything works just perfect. – Anton Nov 24 '18 at 10:08
  • @Anton Are you using my code or have you modified it ?, I do not generate that warning. – eyllanesc Nov 24 '18 at 10:12
  • @Anton If you have modified my code I have probably omitted something in my explanation that maybe you have not implemented, on the other hand if you are using my code without modifying anything could be a problem of versions what version of PyQt5 are you using? – eyllanesc Nov 24 '18 at 10:14
  • I did not modify your code. PyQt5 5.11.3 is used. I also found out, that line `lay = QtWidgets.QVBoxLayout(self)` causes warnings (and any usage of additional layout), but deleting this line will cause QGroupBoxes to shrink again, so I will use your approach anyway. – Anton Nov 24 '18 at 10:20