REF
https://www.jianshu.com/p/3832eb48f3d5
布局(Layout)管理
Qt Designer中,在工具箱中最上方可以看到有4種布局。分別是垂直布局、水平布局、柵格布局和表單布局。
四種布局
布局名稱 布局含義
垂直(Vertical)布局 布局內的控件按照從上到下的順序縱向排列
水平(Horizontal)布局 布局內的控件按照從左到右的順序橫向排列
柵格(Grid)布局 將控件放入柵格中,然后划分成若干行與若干列,並且將每個窗口控件放在合適的單元中
表單(Form)布局 控件以兩列布局在表單中,左列包含標簽,右列包含輸入控件
在Qt Designer中實現布局有兩種方式,通過布局管理器進行布局和通過容器控件進行布局。
布局管理器
讓我們在左側的工具箱中隨意拖動一些諸如按鈕、標簽、輸入框等控件到主窗口中。
很隨意的主窗口
由於剛才是隨意拖拽至主窗口,因此所有控件的排放是亂七八糟的。此時,我們不選中任何控件,在空白處點擊右鍵,找到彈出菜單最下方的Layout布局。
右鍵菜單
可以看到,在右鍵菜單中可以指定布局的方式以及相應布局方式的快捷鍵。這里我們選擇Lay Out Vertically(垂直布局),整個主窗口內的所有控件一瞬間都垂直着排列整齊了。
垂直布局的效果
此時如果需要調整垂直布局的順序,只需按住待調整的控件,上下拖動即可。但是這樣布局是針對整個窗口的,有時我們需要讓不同的布局有父子關系的繼承。那么這時就不能單純地在空白的地方點擊右鍵來布局了。
讓我們再次點擊 右鍵 -> Lay Out -> Break LayOut 來打開(取消)布局。
選中需要水平布局的2個控件(ctrl+鼠標單擊),選中后點擊右鍵,水平布局。再選中另外兩個控件(ctrl+鼠標單擊),選擇水平布局。此時的主窗口應該如圖所示:
2個水平布局
最后,我們再將兩個布局選中(框選),點擊右鍵垂直布局,來排列兩個水平布局。
將兩個水平布局垂直布局
最后在空白區域再次使用垂直布局。這樣即使我們縮放窗口,整個窗口內的控件也會跟着窗口的變化做出相應改變了。
最終效果
在上述操作的過程中,我們的一系列操作有決定這些物體的父子關系(層級關系)。而其層級關系在對象查看器中可以直觀地看出。
對象查看器中的層級關系
布局管理生成的代碼
讓我們把前面制作的布局保存為.ui文件,並使用PyUIC轉換為.py文件。
# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'firstQTui2.ui' # # Created by: PyQt5 UI code generator 5.15.4 # # WARNING: Any manual changes made to this file will be lost when pyuic5 is # run again. Do not edit this file unless you know what you are doing. from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(488, 303) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget) self.verticalLayout_2.setObjectName("verticalLayout_2") self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setObjectName("pushButton") self.horizontalLayout.addWidget(self.pushButton) self.label = QtWidgets.QLabel(self.centralwidget) self.label.setObjectName("label") self.horizontalLayout.addWidget(self.label) self.verticalLayout.addLayout(self.horizontalLayout) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.checkBox = QtWidgets.QCheckBox(self.centralwidget) self.checkBox.setObjectName("checkBox") self.horizontalLayout_2.addWidget(self.checkBox) self.radioButton = QtWidgets.QRadioButton(self.centralwidget) self.radioButton.setObjectName("radioButton") self.horizontalLayout_2.addWidget(self.radioButton) self.verticalLayout.addLayout(self.horizontalLayout_2) self.verticalLayout_2.addLayout(self.verticalLayout) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 488, 21)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.pushButton.setText(_translate("MainWindow", "PushButton")) self.label.setText(_translate("MainWindow", "TextLabel")) self.checkBox.setText(_translate("MainWindow", "CheckBox")) self.radioButton.setText(_translate("MainWindow", "RadioButton"))
從上面的代碼中,我們找到關鍵的幾行。如定義label的時候,是如下代碼:
self.label = QtWidgets.QLabel(self.centralwidget) self.label.setObjectName("label") self.horizontalLayout.addWidget(self.label)
其中,最后一行將label添加為了horizontalLayout的子物體。
self.horizontalLayout_2.addWidget(self.pushButton)
self.verticalLayout_3.addLayout(self.horizontalLayout_2)
self.verticalLayout_4.addLayout(self.verticalLayout_3)
后面的幾行代碼,如verticalLayout_3將horizontalLayout_2作為了其子物體;verticalLayout_4將verticalLayout_3作為了其子物體。這些都是與我們在Qt Designer中做的操作是一樣的。
使用容器進行布局
容器(Container)指的就是能容納其他子控件的一個控件。使用容器控件可以將容器控件中的所有控件歸為一類,從而區別於其他的控件。當然,正如上文提到過的,使用容器也可以對控件進行布局。
工具盒中的容器控件
首先,從左側的Container中拖出一個Frame控件到主窗口中,再拖出一個label、line edit和push button到Frame中。此時Frame中的控件應該是如下圖:
雜亂的Frame
但選中Frame控件,點擊 右鍵-> Lay Out -> Lay Out Horizontally 則會自動水平排列Frame中的三個控件。
水平布局Frame中的控件
當我們需要變更Frame的位置的時候,可以直接拖動Frame到相應地位置,這樣管理更加方便。使用容器進行布局的實質也是使用容器管理器進行布局的。
絕對布局
我們前面的學習重點放在了布局管理器上面。但是最簡單的布局則是之間輸入控件的Geometry屬性值。
屬性編輯器
在屬性編輯器中,我們通過修改X Y值來將控件放置在相應地位置,通過修改Width和Height來更改其高度。讓我們通過如下表格來解讀一下這個Button的Geometry屬性。
名稱 值 含義
X 290 控件的最左上角距離主窗口的左側290px
Y 140 控件的最左上角距離主窗口的上方140px
Width 93 按鈕的寬度為93px
Height 28 按鈕的高度為23px
而上述的Geometry屬性在.py代碼中是如下體現的:
self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setGeometry(QtCore.QRect(290, 140, 93, 28)) self.pushButton.setObjectName("pushButton")
可以看到,上述代碼的第二行通過setGeometry方法指定了Geometry屬性的四個值。通過以上的方法,我們可以對任何一個控件進行布局。
下一篇: PyQT5 入門教程(之三)