Add scrollable regions with QScrollArea
Run out of space in your GUI? Add a scrollable region to your application

When you start building apps that display long documents, large amounts of data or large numbers of widgets, it can be difficult to arrange things within a fixed-size window. Resizing the window beyond the size of the screen isn't an option, and shrinking widgets to fit can make the information unreadable.

To illustrate the problem below is a window in which we've created a large number of QLabel widgets. These widgets have the size Vertical Policy set to Preferred which automatically resizes the widgets down to fit the available space. The results are unreadable.

Problem of Too Many Widgets.png Problem of Too Many Widgets.png

Settings the Vertical Policy to Fixed keeps the widgets at their natural size, making them readable again.

Problem of Too Many Widgets With Fixed Heights Problem of Too Many Widgets With Fixed Heights

However, while we can still add as many labels as we like, eventually they start to fall off the bottom of the layout.

To solve this problem GUI applications can make use of scrolling regions to allow the user to move around within the bounds of the application window while keeping widgets at their usual size. By doing this an almost unlimited amount of data or widgets can be shown, navigated and viewed within a window — although care should be taken to make sure the result is still usable!

In this tutorial, we'll cover adding a scrolling region to your PyQt application using QScrollArea.

Adding a QScrollArea in Qt Designer

First we'll look at how to add a QScrollArea from Qt Designer.

Qt Creator — Select MainWindow for widget type Qt Creator — Select MainWindow for widget type

So we will choose the scroll area widget and add it to our layout as below.

First, create an empty MainWindow in Qt Designer and save it as mainwindow.ui

Add Scroll Area Add Scroll Area

Next choose to lay out the QScrollArea vertically or horizontally, so that it scales with the window.

Lay Out The Scroll Area Vertically Or Horizontally Lay Out The Scroll Area Vertically Or Horizontally

Voila, we now have a completed scroll area that we can populate with anything we need.

The Scroll Area Is Created The Scroll Area Is Created

Inserting Widgets

We will now add labels to that scroll area. Lets take two labels and place it inside the QScrollArea. We will then proceed to right click inside the scroll area and select Lay Out Vertically so our labels will be stacked vertically.

Add Labels to The Scroll Area And Set the Layout Add Labels to The Scroll Area And Set the Layout

We've set the background to blue so the illustration of this this works is clear. We can now add more labels to the QScrollArea and see what happens. By default, the Vertical Policy of the label is set to Preferred which means that the label size is adjusted according to the constraints of widgets above and below.

Next, we'll add a bunch of widgets.

Adding More Labels to QScrollArea Adding More Labels to QScrollArea

Any widget can be added into a `QScrollArea` although some make more sense than others. For example, it's a great way to show multiple widgets containing data in a expansive dashboard, but less appropriate for control widgets — scrolling around to control an application can get frustrating.

Note that the scroll functionality has not been triggered, and no scrollbar has appeared on the right hand side. Instead the labels are still progressively getting smaller in height to accommodate the widgets.

However, if we set Vertical Policy to Fixed and set the minimumSize of height to 100px the labels will no longer be able to shrink vertically into the available space. As the layout overflows this will now trigger the QScrollArea to display a scrollbar.

Setting Fixed Heights for Labels Setting Fixed Heights for Labels

With that, our scrollbar appears on the right hand side. What has happened is that the scroll area only appears when necessary. Without a fixed height constraint on the widget, Qt assumes the most logical way to handle the many widgets is to resize them. But by imposing size constraints on our widgets, the scroll bar appears to allow all widgets to keep their fixed sizes.

Another important thing to note is the properties of the scroll area. Instead of adjusting fixed heights, we can keep it in Preferred , we can set the properties of the verticalScrollBar to ScrollBarAlwaysOn which will enable the scroll bar to appear sooner as below

ScrollArea Properties ScrollArea Properties

Saving and running the code at the start of this tutorial gives us this scroll area app which is what we wanted.

App With Scroll Bar App With Scroll Bar

Adding a QScrollArea from code

As with all widgets you can also add a QScrollArea directly from code. Below we repeat the above example, with a flexible scroll area for a given number of widgets, using code.

python
from PySide6.QtWidgets import (QWidget, QSlider, QLineEdit, QLabel, QPushButton, QScrollArea,QApplication,
                             QHBoxLayout, QVBoxLayout, QMainWindow)
from PySide6.QtCore import Qt, QSize
from PySide6 import QtWidgets
import sys


class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()

        self.scroll = QScrollArea()             # Scroll Area which contains the widgets, set as the centralWidget
        self.widget = QWidget()                 # Widget that contains the collection of Vertical Box
        self.vbox = QVBoxLayout()               # The Vertical Box that contains the Horizontal Boxes of  labels and buttons

        for i in range(1,50):
            object = QLabel("TextLabel")
            self.vbox.addWidget(object)

        self.widget.setLayout(self.vbox)

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

        self.setCentralWidget(self.scroll)

        self.setGeometry(600, 100, 1000, 900)
        self.setWindowTitle('Scroll Area Demonstration')
        self.show()


app = QtWidgets.QApplication(sys.argv)
main = MainWindow()
sys.exit(app.exec_())

If you run the above code you should see the output below, with a custom widget repeated multiple times down the window, and navigable using the scrollbar on the right.

Scroll Area App Scroll Area App

Next, we'll step through the code to explain how this view is constructed.

First we create our layout hierarchy. At the top level we have our QMainWindow which we can set the QScrollArea onto using .setCentralWidget. This places the QScrollArea in the window, taking up the entire area.

To add content to the QScrollArea we need to add a widget using .setWidget, in this case we are adding a custom QWidget onto which we have applied a QVBoxLayout containing multiple sub-widgets.

python
    self.scroll = QScrollArea()             # Scroll Area which contains the widgets, set as the centralWidget
    self.widget = QWidget()                 # Widget that contains the collection of Vertical Box
    self.vbox = QVBoxLayout()               # The Vertical Box that contains the Horizontal Boxes of  labels and buttons

    for i in range(1,50):
        object = QLabel("TextLabel")
        self.vbox.addWidget(object)

This gives us the following hierarchy in the window:

Finally we set up properties on the QScrollArea, setting the vertical scrollbar Always On and the horizontal Always Off. We allow the widget to be resized, and then add the central placeholder widget to complete the layout.

python
#Scroll Area Properties
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scroll.setWidgetResizable(True)
self.scroll.setWidget(self.widget)

Finally, we will add the QScrollArea as the central widget for our QMainWindow and set up the window dimensions, title and show the window.

python
self.setCentralWidget(self.scroll)

self.setGeometry(600, 100, 1000, 900)
self.setWindowTitle('Scroll Area Demonstration')
self.show()

Create GUI Applications with Python & Qt5
The easy way to create desktop applications

The complete guide to building GUI applications with PySide2. From the basics of creating a desktop window to the key features you need to build real apps.

Downloadable ebook (PDF, ePub) & Complete Source code

To support developers in [[ countryRegion ]] I give a [[ localizedDiscount[couponCode] ]]% discount with the code [[ couponCode ]] — Enjoy!

For [[ activeDiscount.description ]] I'm giving a [[ activeDiscount.discount ]]% discount with the code [[ couponCode ]] — Enjoy!

Conclusion.

In this tutorial we've learned how to add a scrollbar with an unlimited number of widgets, programmatically or using Qt Designer. Adding a QScrollArea is a good way to include multiple widgets especially on apps that are data intensive and require objects to be displayed as lists.

Have a go at making your own apps with QScrollArea and share with us what you have made!

For more information about using QScrollArea check out the PyQt5 documentation.

Add scrollable regions with QScrollArea was written by John Lim .

John is a developer from Kuala Lumpur, Malaysia who works as a Senior R&D Engineer.

Interested in contributing to the site? Find out more.

Continue reading

QComboBox  pyside

The QComboBox is a simple widget for presenting a list of options to your users in PyQt, taking up the minimum amount of screen space. The widget can have a single selected item, which is displayed in the widget area. When selected a QComboBox pops out a list of possible values from which you can select. A QComboBox can also - optionally - be made editable, so your users can enter their own values onto the list of possible values. QComboBox in its closed and open state Populating a QComboBox Items can be added or inserted to a QComboBox, where adding appends the item to the end of the current list, while insert inserts them in a specific index in the existing list. There are convenience methods for adding multiple items to a combobox and also for adding icons to the list. The following example will demonstrate each of these using a series of comboboxes. python from PyQt5.QtWidgets import QComboBox, QMainWindow, QApplication, QWidget, QVBoxLayout from PyQt5.QtGui import QIcon import sys class MainWindow(QMainWindow): def __init__(self): super().__init__() combobox1 = QComboBox() combobox1.addItem('One') combobox1.addItem('Two') combobox1.addItem('Three') combobox1.addItem('Four') combobox2 = QComboBox() combobox2.addItems(['One', 'Two', 'Three', 'Four']) combobox3 = QComboBox() combobox3.addItems(['One', 'Two', 'Three', 'Four']) combobox3.insertItem(2, 'Hello!') combobox4 = QComboBox() combobox4.addItems(['One', 'Two', 'Three', 'Four']) combobox4.insertItems(2, ['Hello!', 'again']) combobox5 = QComboBox() icon_penguin = QIcon('animal-penguin.png') icon_monkey = QIcon('animal-monkey.png') icon_bauble = QIcon('bauble.png') combobox5.addItem(icon_penguin, 'Linux') combobox5.addItem(icon_monkey, 'Monkeyix') combobox5.insertItem(1, icon_bauble, 'Baublix') layout = QVBoxLayout() layout.addWidget(combobox1) layout.addWidget(combobox2) layout.addWidget(combobox3) layout.addWidget(combobox4) layout.addWidget(combobox5) container = QWidget() container.setLayout(layout) self.setCentralWidget(container) def current_text_changed(self, s): print("Current text: ", s) app = QApplication(sys.argv) w = MainWindow() w.show() app.exec_() Run the example and compare the result with each series of add and insert steps. Adding items to a QComboBox You can replace the text at a specific index in the list by calling .setItemText() for example. python widget.setItemText(3, 'new text') Finally, you can clear a QComboBox -- removing all items in it -- by calling .clear(). python widget.clear() QComboBox signals The QComboBox emits a number of signals on state changes. When the currently selected item changes, the widget emits .currentIndexChanged() and .currentTextChanged() signals. The first receives the index of the selected entry while the second receives the text of that item. There is a further signal .activated() which is emitted for user-selections whether the index is changed or not: selecting the same entry again will still emit the signal. Highlighting an entry in the QComboBox popup list will emit the .highlighted() signal. The following example demonstrates these signals in action. python from PyQt5.QtWidgets import QComboBox, QMainWindow, QApplication import sys class MainWindow(QMainWindow): def __init__(self): super().__init__() combobox = QComboBox() combobox.addItems(['One', 'Two', 'Three', 'Four']) # Connect signals to the methods. combobox.activated.connect(self.activated) combobox.currentTextChanged.connect(self.text_changed) combobox.currentIndexChanged.connect(self.index_changed) self.setCentralWidget(combobox) def activated(Self, index): print("Activated index:", index) def text_changed(self, s): print("Text changed:", s) def index_changed(self, index): print("Index changed", index) app = QApplication(sys.argv) w = MainWindow() w.show() app.exec_() If you run the example the signals emitted as you interact with the QComboBox will be shown in the console, giving output like that shown below. Note that when re-selecting the same entry, only the .activated() signal is emitted. python Index changed 1 Text changed: Two Activated index: 1 Index changed 2 Text changed: Three Activated index: 2 Index changed 3 Text changed: Four Activated index: 3 Activated index: 3 Activated index: 3 Getting the current state In addition to the signals, QComboBox has a few methods for getting the current state at any time. For example, you can use .currentIndex() to get the index of the currently selected item in the combobox, or use .currentText() to get the text. With the index you can also look up the text of a specific item using .itemText(). Finally, you can use .count() to get the total number of items in the combobox list. In the example below, we use the activated signal we've already seen to hook up a number of methods which get information about the combobox and display this in the console. As you select any item in the combobox every method will run printing a message to the console. python from PyQt5.QtWidgets import QComboBox, QMainWindow, QApplication import sys class MainWindow(QMainWindow): def __init__(self): super().__init__() # Keep a reference to combobox on self, so we can access it in our methods. self.combobox = QComboBox() self.combobox.addItems(['One', 'Two', 'Three', 'Four']) # Connect signal to our methods. self.combobox.activated.connect(self.check_index) self.combobox.activated.connect(self.current_text) self.combobox.activated.connect(self.current_text_via_index) self.combobox.activated.connect(self.current_count) self.setCentralWidget(self.combobox) def check_index(self, index): cindex = self.combobox.currentIndex() print(f"Index signal: {index}, currentIndex {cindex}") def current_text(self, _): # We receive the index, but don't use it. ctext = self.combobox.currentText() print("Current text", ctext) def current_text_via_index(self, index): ctext = self.combobox.itemText(index) # Get the text at index. print("Current itemText", ctext) def current_count(self, index): count = self.combobox.count() print(f"Index {index+1}/{count}") app = QApplication(sys.argv) w = MainWindow() w.show() app.exec_() Running this and selecting different items in the combobox will show the outputs. python Current text Two Current itemText Two Index 1/4 Index signal: 2, currentIndex 2 Current text Three Current itemText Three Index 2/4 Index signal: 3, currentIndex 3 Current text Four Current itemText Four Index 3/4 Editable comboboxes You can set a QComboBox to be editable allowing the user to type enter the values not currently in the list. Entered values can be added to the list, or just used as a value which is not inserted. To enable editing you can call .setEditable(True) on the widget, while control of how inserts operate is handled through the insert policy. This is set by calling .setInsertPolicy() passing one of the following flags: Flag Value Behavior QComboBox.NoInsert 0 No insert QComboBox.InsertAtTop 1 Insert as first item QComboBox.InsertAtCurrent 2 Replace currently selected item QComboBox.InsertAtBottom 3 Insert after last item QComboBox.InsertAfterCurrent 4 Insert after current item QComboBox.InsertBeforeCurrent 5 Insert before current item QComboBox.InsertAlphabetically 6 Insert in alphabetical order For PyQt6 use the fully-qualified flag name, i.e. QComboBox.InsertPolicy.NoInsert For example, to insert new values alphabetically, you would use. python widget.setInsertPolicy(QComboBox.InsertAlphabetically) If the combobox is set to be editable, but QComboBox.NoInsert is set as the insert policy, users will be able to enter their own custom values, but they will not be added to the list. In the following example we have two QComboBox widgets: one which is our editable box and the second which controls the insert policy of the first. Note that since the values of the flags (see above) are just numbers from 0 to 6, we can use the index to determine the flag. python from PyQt5.QtWidgets import QComboBox, QMainWindow, QApplication, QWidget, QVBoxLayout import sys class MainWindow(QMainWindow): def __init__(self): super().__init__() # Keep a reference to combobox on self, so we can access it in our methods. self.combobox = QComboBox() self.combobox.addItems(['One', 'Two', 'Three', 'Four']) self.combobox.setEditable(True) self.combobox.currentTextChanged.connect(self.current_text_changed) # Insert policies self.insertpolicy = QComboBox() self.insertpolicy.addItems([ 'NoInsert', 'InsertAtTop', 'InsertAtCurrent', 'InsertAtBottom', 'InsertAfterCurrent', 'InsertBeforeCUrrent', 'InsertAlphabetically' ]) # The index in the insertpolicy combobox (0-6) is the correct flag value to set # to enable that insert policy. self.insertpolicy.currentIndexChanged.connect(self.combobox.setInsertPolicy) layout = QVBoxLayout() layout.addWidget(self.combobox) layout.addWidget(self.insertpolicy) container = QWidget() container.setLayout(layout) self.setCentralWidget(container) def current_text_changed(self, s): print("Current text: ", s) app = QApplication(sys.argv) w = MainWindow() w.show() app.exec_() If you run this example you'll notice you can now type into the (top) editable combobox and submit them by pressing Enter. The .currentTextChanged() signal will be emitted as you type into the field. python Current text: w Current text: wq Current text: wqe Current text: wqew Current text: wqeww Current text: wqewwq Current text: wqewwqe By default the insert policy is set to QComboBox.NoInsert so entered values will not be added, just set as the value of the combobox. By selecting the insert policy in the second combobox you can change this behavior, having new entries added to the list. Editing a QComboBox with insert policy When you allow users to add values to the list, you may wish to constrain the maximum number of entries. This can be done using .setMaxCount, e.g. python widget.setMaxCount(10) More