-
Notifications
You must be signed in to change notification settings - Fork 0
Qt Style
We do not use designer, composer or other layout languages, just Qt in Python. So there is just one language to know: Python. Others may prefer to use additional tools, but they are not used in this app ( at least so far ).
We us a library call qtpy which is a compatibility layer that lets the underlying Qt code be Qt5, or Qt6 or Pyside.....
Qt uses C conventions, method names are in Camel case ours are in Snake Case, the Python convention. We find this useful because it helps distinguish between native Qt cod and ours
The style of QT programming here seems to differ quite a bit from what I get from a Chat Bot. I assume this is modeled on most code that it has read. For example: Claude, using python and qt6, could you give me a qt6 widget as a window with 3 qpushbuttons alternating with 3 qlablewidgets layout these on 3 lines. Do not use loops, just basic straight line code.
Claud wrote a short app, part of which was this:
# --- Row 1 ---
self.button1 = QPushButton("Button 1")
self.label1 = QLabel("Label 1")
self.label1.setAlignment(Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft)
self.button1.clicked.connect(self.on_button1_clicked)
row1 = QHBoxLayout()
row1.addWidget(self.button1)
row1.addWidget(self.label1)
# --- Row 2 ---
self.button2 = QPushButton("Button 2")
self.label2 = QLabel("Label 2")
self.label2.setAlignment(Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft)
self.button2.clicked.connect(self.on_button2_clicked)
row2 = QHBoxLayout()
row2.addWidget(self.button2)
row2.addWidget(self.label2)
............ skip some code ......
# --- Main layout ---
main_layout = QVBoxLayout()
main_layout.addLayout(row1)
main_layout.addLayout(row2)
main_layout.addLayout(row3)
We would refactor the code to:
# ---- Main layout
main_layout = QVBoxLayout()
main_layout.setSpacing(12)
main_layout.setContentsMargins(20, 20, 20, 20)
self.setLayout(main_layout)
# --- Row 1 ---
row_layout = QHBoxLayout()
main_layout.addLayout(row_layout)
widget = QPushButton("Button 1")
self.button1 = widget
widget.clicked.connect( self.on_button1_clicked )
row_layout.addWidget( widget )
widget = QLabel("Label 1")
self.label1 = widget
widget.setAlignment(Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft)
row_layout.addWidget( widget )
# --- Row 2 ---
row_layout = QHBoxLayout()
main_layout.addLayout(row_layout)
widget = QPushButton("Button 2")
self.button2 = widget
widget.clicked.connect( self.on_button2_clicked )
row_layout.addWidget( widget )
widget = QLabel("Label 2")
self.label2 = widget
widget.setAlignment(Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft)
row_layout.addWidget( widget )
# --- Row 3 ---
row_layout = QHBoxLayout()
main_layout.addLayout(row_layout)
widget = QPushButton("Button 3")
self.button1 = widget
widget.clicked.connect( self.on_button3_clicked )
row_layout.addWidget( widget )
widget = QLabel("Label 3")
self.label3 = widget
widget.setAlignment(Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft)
row_layout.addWidget( widget )
So how is this different:
- Larger elements are created first, layouts before the widgets place in them.
- Layouts are place in their parents as soon as they are created, and then widgets are place in the layouts as soon as the widgets are created.
- Generic local variables are used over instance variables. If you look at the code you will see that this makes code between the different rows more identical, making copy and paste work well. All widgets are locally named widget, and the active layout is usually called layout.
- In much code the assignment of widget to an instance variable as self.lable3 = widget is not even needed and in fact the assignment of buttons to instance variables is not needed in this example ( to see this you would need the full example, the code may be in the repo .... )
We think of the windows as being layout from left to right and then down the window just the way you read a page. This give a linear flow to the layout and this is reflected in the code, from left to right and down the source code.
The refactoring above make it relatively easy to move an element on the page just by cutting and pasting it to a new position in the code. The style above makes it relatively When code would have several layout active at the same time we often move some of the code to a new method where confusing variables are now out of scope. This makes generic names like layout and widget work without conflict.
Some code uses models and views, often several different ones on the same window widget. In that case the code for manipulating a model or view is put in a method and a generic local variable is assigned to the model or view for the rest of the method.
view = self.picture_view ......
The same style may also be used with other Python objects which are mutable and often acted on using their own methods.