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:
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:
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:
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:
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:
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:
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)
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:
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) -> None
Code 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:
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 theQVBoxLayout
object to add a vertical spacer to the layout to align widgets at the top, bottom, or center. - Use the
setStretchFactor()
method of theQVBoxLayout
object to set a stretch factor for a widget in the layout. - Use the
setSpacing()
method of theQVBoxLayout
object to set the spaces between child widgets. - Use the
setContentsMargins()
method of theQVBoxLayout
object to set the left, top, right, and bottom margins of the contents.