PyQt: Adding widgets to scrollarea during the runtime

lucaboni picture lucaboni · Mar 7, 2014 · Viewed 9.4k times · Source

I'm trying to add new widgets (in the example below I use labels) during the runtime by pressing on a button. Here the example:

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class Widget(QWidget):

    def __init__(self, parent= None):
        super(Widget, self).__init__()

        btn_new = QPushButton("Append new label")
        self.connect(btn_new, SIGNAL('clicked()'), self.add_new_label)

        #Container Widget       
        self.widget = QWidget()
        #Layout of Container Widget
        layout = QVBoxLayout(self)
        for _ in range(20):
            label = QLabel("test")
            layout.addWidget(label)
        self.widget.setLayout(layout)

        #Scroll Area Properties
        scroll = QScrollArea()
        scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        scroll.setWidgetResizable(False)
        scroll.setWidget(self.widget)

        #Scroll Area Layer add
        vLayout = QVBoxLayout(self)
        vLayout.addWidget(btn_new)
        vLayout.addWidget(scroll)
        self.setLayout(vLayout)

    def add_new_label(self):
        label = QLabel("new")
        self.widget.layout().addWidget(label)


if __name__ == '__main__':
    app = QApplication(sys.argv)

    dialog = Widget()
    dialog.show()

    app.exec_()

When I start the application everything looks ok, the list of labels is correctly shown and their size is also correct. But, when I press several times on the button to add new labels, the new ones are added to the list but their size change. All labels of the list go smaller.

How do I fix this error?

Answer

ekhumoro picture ekhumoro · Mar 7, 2014

The problem is the line:

    scroll.setWidgetResizable(False)

which obviously stops the widget resizing when you add more child widgets to it (and so they all get squashed together in the same space).

So reset it to True and add a stretchable space to the bottom of the widget's layout:

    layout.addStretch()
    self.widget.setLayout(layout)
    ...
    scroll.setWidgetResizable(True)
    scroll.setWidget(self.widget)

then insert the new labels before the spacer:

    def add_new_label(self):
        label = QLabel("new")
        layout = self.widget.layout()
        layout.insertWidget(layout.count() - 1, label)