Python Forum

Full Version: QScrollArea with a gridlayout
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I have a form that grows in height as the user provides information. Currently this occurs by dynamically adding tables and other widgets to a grid layout as the user enters information. The simplified starting point is something like this:

class UI(QtGui.QDialog):

    def __init__(self, parent=None):
        QtGui.QDialog.__init__(self, parent)
        self.setObjectName(_fromUtf8("Form"))
        self.resize(800, 600)
        self.gridLayout = QtGui.QGridLayout()
        self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
        self.setLayout(self.gridLayout)
Eventually, enough widgets may be added to the grid layout so the dialog content exceeds its height. Given this, I would like to implement the grid layout within the scroll area, but I can't seem to get things quite right:

class UI(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QDialog.__init__(self, parent)        

    def setupUi(self):
        self.setObjectName(_fromUtf8("Form"))
        screen = QtGui.QDesktopWidget().screenGeometry()
        self.resize(800, screen.height())
        self.gridLayout = QtGui.QGridLayout()
        self.gridLayout.setObjectName(_fromUtf8("gridLayout"))

        w = QtGui.QWidget()
        # w.setLayout(self.gridLayout)

        s = QtGui.QScrollArea()
        s.setMinimumHeight(screen.height())
        s.setWidget(w)
        s.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        s.setLayout(self.gridLayout)

        l = QtGui.QVBoxLayout()
        l.setContentsMargins(0, 0, 0, 0)
        l.setSpacing(0)
        l.addWidget(s)

        # self.setLayout(self.gridLayout)
        self.setLayout(l)
Where am I going wrong? I have a scroll area and a scroll bar, but the contents that get added don't seem to be within the scrollable area? Any guidance is greatly appreciated.
From QtCreator output, this is how widgets should be added to a scroll area:

        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.scrollArea = QtWidgets.QScrollArea(self.centralwidget)
        self.scrollArea.setWidgetResizable(True)
        self.scrollAreaWidgetContents = QtWidgets.QWidget()
        self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 379, 207))
        self.verticalLayout = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents)
        self.tableWidget = QtWidgets.QTableWidget(self.scrollAreaWidgetContents)

        self.verticalLayout.addWidget(self.tableWidget)
        self.scrollArea.setWidget(self.scrollAreaWidgetContents)
        self.gridLayout.addWidget(self.scrollArea, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
It would help if you could provide a working example of what you are trying to do.
Here is a more complete example. As you select combo options, and add sections. The scrollbar does not appear, and after adding enough elements they become unusable.

from PyQt4 import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName(_fromUtf8("Form"))
        Form.resize(800, 600)
        Form.setWindowTitle(_fromUtf8(""))
        self.gridLayout = QtGui.QGridLayout(Form)
        self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
        self.horizontalLayout_2 = QtGui.QHBoxLayout()
        self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2"))
        self.btnAddSection = QtGui.QPushButton(Form)
        self.btnAddSection.setMinimumSize(QtCore.QSize(0, 30))
        self.btnAddSection.setMaximumSize(QtCore.QSize(140, 30))
        self.btnAddSection.setObjectName(_fromUtf8("btnAddSection"))
        self.btnAddSection.clicked.connect(self.add_section_button_clicked)
        self.horizontalLayout_2.addWidget(self.btnAddSection)
        self.btnApply = QtGui.QPushButton(Form)
        self.btnApply.setMinimumSize(QtCore.QSize(0, 30))
        self.btnApply.setObjectName(_fromUtf8("btnApply"))
        self.horizontalLayout_2.addWidget(self.btnApply)
        self.gridLayout.addLayout(self.horizontalLayout_2, 1, 0, 1, 1)
        self.verticalLayout = QtGui.QVBoxLayout()
        self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
        self.horizontalLayout = QtGui.QHBoxLayout()
        self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
        self.lblTitle = QtGui.QLabel(Form)
        self.lblTitle.setMinimumSize(QtCore.QSize(0, 30))
        self.lblTitle.setAlignment(QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop)
        self.lblTitle.setObjectName(_fromUtf8("lblTitle"))
        self.horizontalLayout.addWidget(self.lblTitle)
        self.verticalLayout.addLayout(self.horizontalLayout)
        self.verticalLayout_2 = QtGui.QVBoxLayout()
        self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2"))
        self.scrollArea = QtGui.QScrollArea(Form)
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setObjectName(_fromUtf8("scrollArea"))
        self.scrollAreaWidgetContents_2 = QtGui.QWidget()
        self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 776, 500))
        self.scrollAreaWidgetContents_2.setObjectName(_fromUtf8("scrollAreaWidgetContents_2"))
        self.formLayoutWidget = QtGui.QWidget(self.scrollAreaWidgetContents_2)
        self.formLayoutWidget.setGeometry(QtCore.QRect(0, 0, 761, 521))
        self.formLayoutWidget.setObjectName(_fromUtf8("formLayoutWidget"))
        self.formLayout = QtGui.QFormLayout(self.formLayoutWidget)
        self.formLayout.setVerticalSpacing(10)
        self.formLayout.setObjectName(_fromUtf8("formLayout"))

        self.scrollArea.setWidget(self.scrollAreaWidgetContents_2)
        self.verticalLayout_2.addWidget(self.scrollArea)
        self.verticalLayout.addLayout(self.verticalLayout_2)
        self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)

        self.add_section_button_clicked()
        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        self.btnAddSection.setText(_translate("Form", "Add Section", None))
        self.btnApply.setText(_translate("Form", "APPLY", None))
        self.lblTitle.setText(_translate("Form", "Scrolling Test", None))
        # self.btnDeleteSection.setText(_translate("Form", "Delete Section", None))

    def add_section_button_clicked(self):
        print("add a new section")
        self.add_section_dropdown()

    def add_section_dropdown(self):
        combo = QtGui.QComboBox()
        option_list = ['Choose...', 'One', 'Two', 'Three']
        combo.addItems(option_list)
        combo.activated[str].connect(self.combo_selection_changed)
        combo.setParent(self.formLayoutWidget)
        self.formLayout.addRow(combo)

    def combo_selection_changed(self, selection):
        print(selection)
        self.add_table(selection)

    def add_table(self, selection):
        print("adding table: " + str(selection))
        tbl = QtGui.QTableWidget(3,4)
        tbl.setParent(self.formLayoutWidget)
        tbl.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        tbl.setAlternatingRowColors(True)
        tbl.setObjectName(selection)
        self.formLayout.addRow(tbl)


if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    Form = QtGui.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    Form.show()
    sys.exit(app.exec_())
Please note that this deviates from my original goal of a grid layout in a scroll area, in the sense that this approach utilizes a QVBoxLayout.

I read where it is possible to use a gridlayout, but first the layout must be put in to a qwidget.