This is a tutorial on layout management in PyQt.
Learning how to create a few basic widgets is pretty good, but there’s no meaning to it unless you’re able to present them to your user in an acceptable manner. By default, there is no order to any of the widgets. There is no spacing between them, no margins with the edges of window and no proper layout management across the PyQt window.
Uptil this point, you may have been using the
move method, however this isn’t the right way of doing it. PyQt comes with special widgets called layout managers which are specially to deal with placement of widgets inside the window.
We’ll be going through the following PyQt layout managers here:
Before we proceed onto the layout managers, we’ll do a small demonstration using the
move method. Even if it’s not the recommended way, it’s still a form of layout management in PyQt.
move method takes two parameters, a
X coordinate and a
Y coordinate. Remember, the top-left hand corner has the coordinates (0,0) and they increase from top to bottom and left to right.
import sys from PyQt5.QtWidgets import QWidget, QPushButton, QApplication class PyQtLayout(QWidget): def __init__(self): super().__init__() self.UI() def UI(self): Button1 = QPushButton('PyQt', self) Button1.move(20, 10) Button2 = QPushButton('Layout', self) Button2.move(40, 50) Button3 = QPushButton('Management', self) Button3.move(60, 90) self.setGeometry(300, 300, 250, 200) self.setWindowTitle('PyQt5 Layout Management') self.show() def main(): app = QApplication(sys.argv) ex = PyQtLayout() sys.exit(app.exec_()) if __name__ == '__main__': main()
The problem here lies in the fact that the positioning is “Absolute”. This means that if the window is resized or adjusted in any way, the widgets will not change their position to accommodate this new change.
This isn’t a problem with layout managers though which will auto adjust the widgets according to how the window is manipulated/resized.
The QVBoxLayout is a special type of layout which arranges all the widgets inside it in a vertical column. The order in which you add the widgets to the layout changes how they appear in the PyQt window.
First we’ll have to create the layout object using the
QVBoxLayout Class. We’ll use the
addWidget() method on the layout object we created to add the widgets we created to it.
Finally, the most important is to actually add the layout we created to the window we made. In our class based approach, we just have to use the
setLayout() function on “self” which represents the GUI window.
import sys from PyQt5.QtWidgets import (QWidget, QPushButton, QApplication, QHBoxLayout, QVBoxLayout, QGridLayout) class PyQtLayout(QWidget): def __init__(self): super().__init__() self.UI() def UI(self): Button1 = QPushButton('PyQt') Button2 = QPushButton('Layout') Button3 = QPushButton('Management') vbox = QVBoxLayout() vbox.addWidget(Button1) vbox.addWidget(Button2) vbox.addWidget(Button3) self.setLayout(vbox) self.setGeometry(300, 300, 250, 150) self.setWindowTitle('PyQt5 Layout') self.show()
The GUI output:
As you can see from the image below there is already some spacing between the widgets as well as some margins between the widgets and the edge of the window. The default settings are good, but sometimes we may wish to alter them. We have the following two functions for this purpose.
setSpacing(n) function is used to adjust the spacing between the widgets, just pass a number into the brackets of the function.
setContentsMargins(0,0,0,0) function controls the margins between the outermost widget and the GUI window. It takes four parameters, one for each side.
The above two functions work on any layout, not just QVBoxLayout.
QHBoxLayout has the same concept and functionality as QVBoxLayout with a slight change. Instead of vertically stacked widgets, the widgets here are placed side by side in a row.
Except for the changes to the initialization of the layout, there is no other change from how we created the QVBoxLayout.
class PyQtLayout(QWidget): def __init__(self): super().__init__() self.UI() def UI(self): Button1 = QPushButton('PyQt') Button2 = QPushButton('Layout') Button3 = QPushButton('Management') hbox = QHBoxLayout() hbox.addWidget(Button1) hbox.addWidget(Button2) hbox.addWidget(Button3) self.setLayout(hbox) self.setGeometry(300, 300, 200, 200) self.setWindowTitle('PyQt5 Layout') self.show()
The GUI output of the above example:
A very popular type of layout management that you’ll find in many other GUI libraries, the PyQt QGridLayout.
Below is a small grid we created to show you how the coordinates system in the QGridLayout works. The first number in the pair represents the row number, and the second represents the column.
The Grid in the QGridLayout is ever expanding, and will keep increasing as you add widgets. The above image is just for explanatory purposes, (3, 3) isn’t a limit to it’s size or anything.
The only significant change here is that when you’re adding a new widget into the layout, you have to specify the row and column number as the second and third parameter respectively.
class PyQtLayout(QWidget): def __init__(self): super().__init__() self.UI() def UI(self): Button1 = QPushButton('Up') Button2 = QPushButton('Left') Button3 = QPushButton('Right') Button4 = QPushButton('Down') grid = QGridLayout() grid.addWidget(Button1, 0, 1) grid.addWidget(Button2, 1, 0) grid.addWidget(Button3, 1, 2) grid.addWidget(Button4, 1, 1) self.setLayout(grid) self.setGeometry(300, 300, 200, 200) self.setWindowTitle('PyQt5 Layout') self.show()
The GUI output:
You can get even more creative with your layouts by creating multiple layouts and nesting them into each other. This allows you to create more complex and good looking layouts for your PyQt5 window. For example, you can insert a QHBoxLayout into a QVBoxLayout.
Remember, you can nest Layouts within each other as well, using the
Learn more about PyQt5 and it’s widgets from our PyQt5 tutorial series!
This marks the end of the PyQt Layout management article. Any suggestions or contributions for CodersLegacy are more than welcome. Questions regarding the article content can be asked in the comments section below.