Search code examples
pythonwidgetpysideqscrollarea

Add widgets on the fly in pyside


Very new to pyside so maybe a stupid question. I want to create a pyside UI which has a variable number of items in it and also has the possibility to add items while it is running and to make it even more complex it also needs a scroll bar to fit it all on screen!

This is what I've got right now:

import sys

from PySide import QtGui
from PySide import QtCore 
class example(QtGui.QWidget):

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

        grid = QtGui.QGridLayout()
        grid.setSpacing(10)

        self.widget = QtGui.QWidget()

        self.layout = QtGui.QGridLayout(self)

        for i in range(5):
            btn = QtGui.QPushButton("test"+str(i))
            self.layout.addWidget(btn,i,0)
            btn.clicked.connect(self.buttonClicked)
        self.count = i
        self.widget.setLayout(self.layout)


        self.scroll = QtGui.QScrollArea()
        self.scroll.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.scroll.setWidget(self.widget)

        grid.addWidget(self.scroll,3,0)
        self.setLayout(grid)


    def buttonClicked(self):
        title = QtGui.QLabel('Title'+str(self.count))
        self.layout.addWidget(title,self.count + 1,0)
        self.count += 1
        self.widget.addLayout(self.layout,0)
        self.scroll.addWidget(self.widget,0)


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

    dialog = example()
    dialog.show()

    sys.exit(app.exec_())

But somehow the layout gets messed up when adding items through one of the buttons.

Does anybody have an idea how to fix this?

Thanx!


Solution

  • You're not far off. The key piece you're missing is QScrollArea.setWidgetResizable, which will ensure the scrollarea automatically resizes its viewport to fit the contents.

    I've made some other adjustments to your example and added comments where appropriate:

    class example(QtGui.QWidget):
        def __init__(self, parent= None):
            super(example, self).__init__()
    
            grid = QtGui.QGridLayout()
            grid.setSpacing(10)
    
            self.widget = QtGui.QWidget()
    
            # set the widget as parent of its own layout
            self.layout = QtGui.QGridLayout(self.widget)
    
            for i in range(5):
                btn = QtGui.QPushButton("test"+str(i))
                self.layout.addWidget(btn,i,0)
                btn.clicked.connect(self.buttonClicked)
    
            # following lines are redundant
            # self.count = i
            # self.widget.setLayout(self.layout)
    
            self.scroll = QtGui.QScrollArea()
            # need this so that scrollarea handles resizing
            self.scroll.setWidgetResizable(True)
            # these two lines may not be needed now
            self.scroll.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
            self.scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
    
            self.scroll.setWidget(self.widget)
    
            grid.addWidget(self.scroll, 3, 0)
            self.setLayout(grid)
    
        def buttonClicked(self):
            title = QtGui.QLabel('Title' + str(self.layout.count()))
            self.layout.addWidget(title)
            # following lines are redundant
            # self.layout.addWidget(title, self.count + 1, 0)
            # self.count += 1
            # self.widget.addLayout(self.layout,0)
            # self.scroll.addWidget(self.widget,0)