Every UI need a Layout
沒有Layout的世界是脆弱的,看似整齊的表面之下,隱藏著極為脆弱或是僵化的體制與腐敗,可謂是金玉其外敗絮其內。Layout讓UI再擁有整齊的架構之下,同時保有足夠的彈性。本篇會介紹各種PySide2 中的Layout,包括 QgridLayout, QVBoxLayout, QHBoxLayout, 以及 QFormLayout.
關於Layout
在Qt中的Layout包含了常見的各種類型,包括 vertical, horizontal, grid, 以及form layout. 這邊會一一向大家介紹。
在此之前,先和大家分享一點小技巧,使用layout的大方向 大致上會分為以下幾點:
- 小型多個獨立物件,是VBox 與 HBox 的最愛
- 複雜群組、不規則形狀,肯定是該用Grid
- 最外層,請用Grid的糖衣
- 最後,form除了非常整齊的輸入表格外,能少用就少用
VBoxLayout / HBoxLayout
讓我們由最簡單、最基礎的開始吧。
我利用前幾篇所建構的MainWindow class來做Layout的擴充,加入一個method(方法)來新建VBoxLayout以及HBoxLayout,同時用GridLayout為主Layout來包裹另外兩個Layout。
Source
#!venv/bin/python3
from PySide2.QtWidgets import QWidget
from PySide2.QtWidgets import QMainWindow
from PySide2.QtWidgets import QPushButton
from PySide2.QtWidgets import QVBoxLayout, QHBoxLayout, QGridLayout, QFormLayout
class MainWindow(QMainWindow):
def __init__(self, parent=None):
"""Main window, holding all user interface including.
Args:
parent: parent class of main window
Returns:
None
Raises:
None
"""
super(MainWindow, self).__init__(parent)
self._widget = QWidget()
self._width = 400
self._height = 300
self.setFixedSize(self._width, self._height)
g_layout = QGridLayout()
v_layout = self.build_v_layout()
h_layout = self.build_h_layout()
g_layout.addItem(v_layout, 0, 0, 2, 1)
g_layout.addItem(h_layout, 0, 1, 1, 1)
self._widget.setLayout(g_layout)
self.setCentralWidget(self._widget)
@staticmethod
def build_v_layout():
hello_btn = QPushButton('Hello')
work_btn = QPushButton('Working')
play_btn = QPushButton('Playing')
sleep_btn = QPushButton('Sleeping')
v_layout = QVBoxLayout()
v_layout.addWidget(hello_btn)
v_layout.addWidget(work_btn)
v_layout.addWidget(play_btn)
v_layout.addWidget(sleep_btn)
return v_layout
@staticmethod
def build_h_layout():
hello_btn = QPushButton('Hello')
work_btn = QPushButton('Working')
play_btn = QPushButton('Playing')
sleep_btn = QPushButton('Sleeping')
h_layout = QHBoxLayout()
h_layout.addWidget(hello_btn)
h_layout.addWidget(work_btn)
h_layout.addWidget(play_btn)
h_layout.addWidget(sleep_btn)
return h_layout
GridLayout
上面可以看到我用 addItem()
方法將兩個Layout加入GridLayout之中,這邊提一下,加入Layout需使用 addItem
,而加入物件則需使用 addWidget
方法,如我下方VBoxLayout及HBoxLayout所使用。
權重
GridLayout好用的地方便在於彈性極高,可以透過網格的方式定位,同時支援物件於行列的權重,讓物件可以以不同的比例做呈現。
站长备注:
网格布局中addwidget函数可以传入五个参数,分别如下五个参数
arg__1:PySide2.QtWidgets.QWidget, row:int, column:int, rowSpan:int, columnSpan:int
Widget
水平位置
垂直位置
水平占据网格个数
垂直占据网格个数
备注结束。
以下我修改兩種GridLayout的權重比例
Left Pic:
g_layout.addItem(v_layout, 0, 0, 1, 1)
g_layout.addItem(h_layout, 0, 1, 1, 1)
Right Pic:
g_layout.addItem(v_layout, 0, 0, 2, 1)
g_layout.addItem(h_layout, 0, 1, 1, 1)
FormLayout
我們再加入 build_f_layout
方法來建立FormLayout物件,如下
@staticmethod
def build_form_layout():
hello_btn = QPushButton('Hello')
work_btn = QPushButton('Working')
play_btn = QPushButton('Playing')
sleep_btn = QPushButton('Sleeping')
hello_line = QLineEdit()
work_line = QLineEdit()
play_line = QLineEdit()
sleep_line = QLineEdit()
f_layout = QFormLayout()
f_layout.addRow(hello_btn, hello_line)
f_layout.addRow(work_btn, work_line)
f_layout.addRow(play_btn, play_line)
f_layout.addRow(sleep_btn, sleep_line)
return f_layout
並加入GridLayout中,同時我稍微調整了一下權重
f_layout = self.build_f_layout()
g_layout.addItem(v_layout, 1, 0, 1, 1)
g_layout.addItem(h_layout, 0, 0, 1, 2)
g_layout.addItem(f_layout, 1, 1, 1, 1)
Result
Source Code
完整代碼請看:Layout
結論
Layout在UI中非常實用,其實也不難,但常常會看到新手在學習Qt時使用QtDesigner拉入物件後手動作排版,這種方式只要主視窗的大小一經改動整個畫面就會被切掉或是留白,也非常不美觀,物件距離肯定不對等。
Layout不只能幫忙定位,同時具有讓內容物件等比例縮放的效果,這麼好的東西何不試試看呢?
系列教程下一篇:
[PyQt] PySide2 教程 #5: Signal & Slot