PyQt QVBoxLayout

Summary: in this tutorial, you’ll learn how to use the PyQt QVBoxLayout to arrange widgets vertically.

Introduction to the PyQt QVBoxLayout

The QVBoxLayout divides the parent widget into vertical boxes and places the child widgets sequentially from top to bottom.

This program illustrates how to use the QVBoxLayout class:

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout


class MainWindow(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setWindowTitle('PyQt QVBoxLayout')

        # create a layout
        layout = QVBoxLayout()
        self.setLayout(layout)

        # create buttons and add them to the layout
        titles = ['Find Next', 'Find All', 'Close']
        buttons = [QPushButton(title) for title in titles]
        for button in buttons:
            layout.addWidget(button)

        # show the window
        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())
Code language: Python (python)

Output:

How it works.

First, create a QVBoxLayout object:

layout = QVBoxLayout()Code language: Python (python)

Next, set the layout for the MainWindow by calling its setLayout() method:

self.setLayout(layout)Code language: Python (python)

Then, define a list of three strings that represent button titles:

titles = ['Find Next', 'Find All', 'Close']Code language: JavaScript (javascript)

After that, create three buttons (QPushButton) from the list titles using a list comprehension:

buttons = [QPushButton(title) for title in titles]

Finally, add the buttons to the layout using a for loop:

for button in buttons:
    layout.addWidget(button)Code language: Python (python)

Alignments

The QVBoxLayout stretches each widget type in a specific way. For example, the QVBoxLayout stretches the QPushButton horizontally, not vertically.

It means that when you increase the width of the parent widget, the widths of all the buttons also increase:

PyQt QVBoxLayout - Resize

However, when you increase the height of the parent widget, the heights of the buttons don’t change. More importantly, the QVBoxLayout allocates evenly the spaces of the parent widget to each button:

PyQt QVBoxLayout - Vertical Spaces

When the parent widget has more space for the child widgets, you can align the child widgets within the parent widget using vertical spacers.

Align bottom

To push the buttons to the bottom of the parent widget, you add a vertical spacer at the beginning of the layout by using the addStretch() method of the QVBoxLayout object:

PyQt QVBoxLayout - Align Bottom with a Vertical Spacer
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout


class MainWindow(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setWindowTitle('PyQt QVBoxLayout')

        # create a layout
        layout = QVBoxLayout()
        self.setLayout(layout)

        # add a spacer
        layout.addStretch()
        
        # create buttons and add them to the layout
        titles = ['Find Next', 'Find All', 'Close']
        buttons = [QPushButton(title) for title in titles]
        for button in buttons:
            layout.addWidget(button)

        # show the window
        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())

Code language: Python (python)

If you increase the height of the window, the vertical spacer will stretch to the end of the QVBoxLayout and leaves enough spaces for the buttons:

Align top

Similarly, you can add a vertical spacer as the last item of the layout to push the buttons to the top by calling the addStretch() method after adding the buttons to the layout:

PyQt QVBoxLayout - Align Top with a Vertical Spacer
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout


class MainWindow(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setWindowTitle('PyQt QVBoxLayout')

        # create a layout
        layout = QVBoxLayout()
        self.setLayout(layout)

        # create buttons and add them to the layout
        titles = ['Find Next', 'Find All', 'Close']
        buttons = [QPushButton(title) for title in titles]
        for button in buttons:
            layout.addWidget(button)

        # add a spacer
        layout.addStretch()

        # show the window
        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())

Code language: Python (python)

Align center

To align the buttons in the center of the parent widget, you add a vertical spacer at the beginning and one at the end of the layout like this:

PyQt QVBoxLayout - Align Center with Vertical Spacers
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout


class MainWindow(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setWindowTitle('PyQt QVBoxLayout')

        # create a layout
        layout = QVBoxLayout()
        self.setLayout(layout)

        # add a spacer
        layout.addStretch()

        # create buttons and add them to the layout
        titles = ['Find Next', 'Find All', 'Close']
        buttons = [QPushButton(title) for title in titles]
        for button in buttons:
            layout.addWidget(button)

        # add a spacer
        layout.addStretch()

        # show the window
        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())
Code language: Python (python)

Note that you can add a vertical spacer between the widgets in the QVBoxLayout. For example, the following adds a vertical spacer between the second and third buttons:

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout


class MainWindow(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setWindowTitle('PyQt QVBoxLayout')

        # create a layout
        layout = QVBoxLayout()
        self.setLayout(layout)

        # create buttons
        find_next_btn = QPushButton('Find Next')
        find_all_btn = QPushButton('Find All')
        close_btn = QPushButton('Find All')

        # add the first & second buttons to the layout
        layout.addWidget(find_next_btn)
        layout.addWidget(find_all_btn)

        # add a spacer
        layout.addStretch()

        # add the third button
        layout.addWidget(close_btn)

        # show the window
        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())

Code language: Python (python)

Setting layout stretch factors

The following program displays three QLabel widgets with different background colors red, green, and blue using the QVBoxLayout:

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout


class MainWindow(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setWindowTitle('PyQt QVBoxLayout')

        # create a layout
        layout = QVBoxLayout()
        self.setLayout(layout)

        # create buttons
        label_1 = QLabel()
        label_1.setStyleSheet('QLabel{background-color:red}')
        label_2 = QLabel()
        label_2.setStyleSheet('QLabel{background-color:green}')
        label_3 = QLabel()
        label_3.setStyleSheet('QLabel{background-color:blue}')

        layout.addWidget(label_1)
        layout.addWidget(label_2)
        layout.addWidget(label_3)

        # show the window
        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())Code language: Python (python)

Note that we use the style sheets to set the background color for the QLabel widgets.

Unlike QPushButton widgets, the QLabel widgets stretch both vertically and horizontally when you resize the parent widget:

PyQt QVBoxLayout - QLabel

To allocate spaces for each QLabel widget proportionally, you use the setStretchFactor() method with the following syntax:

setStretchFactor(widget, factor)Code language: Python (python)

The setStretchFactor() method sets a stretch factor for the widget to stretch within the layout. Therefore, you need to setStretchFactor() method after adding the child widgets to the layout.

The following program uses the setStretchFactor() method to set the stretch factors for the first, second, and third QLabel widgets as 1, 2, and 3:

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout


class MainWindow(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setWindowTitle('PyQt QVBoxLayout')

        # create a layout
        layout = QVBoxLayout()
        self.setLayout(layout)

        # create buttons
        label_1 = QLabel('')
        label_1.setStyleSheet('QLabel{background-color:red}')

        label_2 = QLabel('')
        label_2.setStyleSheet('QLabel{background-color:green}')

        label_3 = QLabel('')
        label_3.setStyleSheet('QLabel{background-color:blue}')

        layout.addWidget(label_1)
        layout.addWidget(label_2)
        layout.addWidget(label_3)

        layout.setStretchFactor(label_1, 1)
        layout.setStretchFactor(label_2, 2)
        layout.setStretchFactor(label_3, 3)

        # show the window
        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())

Code language: Python (python)
PyQt QVBoxLayout - Layout Stretch Factor

Because of the stretch factors, the second QLabel widget takes twice as much space as the first one and the third QLabel widget uses space that is three times bigger than the first one.

Setting spaces between widgets

By default, the QVBoxLayout sets a default space between widgets. To change the spaces between widgets, you use the setSpacing() method.

The following example uses the setSpacing() method to set the spaces between QLabel widgets to zero:

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout


class MainWindow(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setWindowTitle('PyQt QVBoxLayout')

        # create a layout
        layout = QVBoxLayout()
        self.setLayout(layout)

        # create buttons
        label_1 = QLabel('')
        label_1.setStyleSheet('QLabel{background-color:red}')

        label_2 = QLabel('')
        label_2.setStyleSheet('QLabel{background-color:green}')

        label_3 = QLabel('')
        label_3.setStyleSheet('QLabel{background-color:blue}')

        layout.addWidget(label_1)
        layout.addWidget(label_2)
        layout.addWidget(label_3)

        layout.setSpacing(0)

        # show the window
        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())

Code language: Python (python)

Output:

PyQt QVBoxLayout - Setting Spaces

Setting content margins

By default, the QVBoxLayout sets specific left, top, right, and bottom margins for a widget. To change the margins, you use the setContentsMargins() method:

setContentsMargins(self, left: int, top: int, right: int, bottom: int) -> NoneCode language: PHP (php)

For example, the following uses the setContentsMargins() method to set the margins for QLabel widgets to zero:

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout


class MainWindow(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setWindowTitle('PyQt QVBoxLayout')

        # create a layout
        layout = QVBoxLayout()
        self.setLayout(layout)

        # create buttons
        label_1 = QLabel('')
        label_1.setStyleSheet('QLabel{background-color:red}')

        label_2 = QLabel('')
        label_2.setStyleSheet('QLabel{background-color:green}')

        label_3 = QLabel('')
        label_3.setStyleSheet('QLabel{background-color:blue}')

        layout.addWidget(label_1)
        layout.addWidget(label_2)
        layout.addWidget(label_3)

        # set the contents margins
        layout.setContentsMargins(0, 0, 0, 0)

        # show the window
        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())

Code language: Python (python)

Output:

PyQt QVBoxLayout - Setting Contents Margins

Summary

  • Use PyQt QVBoxLayout to divide the parent widget into vertical boxes and place the child widgets sequentially from top to bottom.
  • Use the addStretch() method of the QVBoxLayout object to add a vertical spacer to the layout to align widgets at the top, bottom, or center.
  • Use the setStretchFactor() method of the QVBoxLayout object to set a stretch factor for a widget in the layout.
  • Use the setSpacing() method of the QVBoxLayout object to set the spaces between child widgets.
  • Use the setContentsMargins() method of the QVBoxLayout object to set the left, top, right, and bottom margins of the contents.
Did you find this tutorial helpful ?