PyQt的布局管理器layout managers提供了一種用戶友好且高效的方式,可以在GUI上排列圖形組件或小部件,正確布置視窗小部件將使您的GUI應用程式看起來更加優美和專業,學習有效地做到這一點是您使用Python和PyQt進行GUI應用程式開發和運行的一項基本技能,
在本教程中,您將學習:
使用PyQt的
layout managers有什么好處如何使用PyQt的
layout managers在GUI上以編程方式布置視窗小部件如何為您的GUI應用程式選擇正確的
layout manager如何在基于主視窗和基于對話框的應用程式中布置小部件
有了這些知識和技能,您就可以使用Python和PyQt創建具有專業外觀的GUI應用程式,
在GUI上布置圖形元素
在創建圖形用戶界面(GUI)應用程式時,一個常見的問題是如何使圖形組件(按鈕,選單,工具列,標簽等)一致地放置在表單和視窗上,此程序稱為GUI布局(GUI layout,),這是創建GUI應用程式的重要步驟,
之前如果要在視窗上布置圖形組件或視窗小部件,則可以采用以下方法之一:
為視窗上的每個小部件確定并手動設定靜態大小和位置,
動態計算并設定每個小部件的大小和位置,
第一種方法相當直接,但是至少具有以下缺點:
您的視窗將無法調整大小,以不同的螢屏解析度顯示它們時可能會導致問題,
您的標簽可能不能正確地支持本地化,因為給定文本的長度在不同語言之間會發生變化,
您的視窗小部件在不同平臺上的顯示方式將有所不同,這使得撰寫看起來不錯的多平臺應用程式變得困難,
第二種方法更靈活,但是,它也有缺點:
您必須進行大量手動計算才能確定每個小部件的正確大小和位置,
您必須做一些額外的計算才能正確回應視窗大小調整,
每當您修改視窗布局時,都必須重做所有計算,
即使您仍然可以使用這兩種方法中的任何一種來布局GUI,大多數時候您可能還是希望使用由最先進的GUI框架或工具包實作的第三種且更方便的方法:布局管理器layout managers,注意:在某些GUI框架(例如Tkinter)中,布局管理器也稱為geometry managers,
layout managers會根據您的特定需求自動在GUI上排列小 部件,它避免了第一種方法的兼容性缺點以及第二種方法的復雜計算,
在以下各節中,您將了解PyQt的內置布局管理器以及如何使用它們有效地布局GUI應用程式的圖形組件,
多樣的PyQt布局形式
在PyQt中,小部件是用作GUI應用程式構建塊的圖形組件,將一堆小部件放在視窗上以創建GUI時,需要給它們一些順序,您需要設定視窗小部件的大小和在視窗上的位置,還需要定義當用戶調整基礎視窗大小時它們的行為,
注意:PyQt5的官方檔案中有一些不完整的部分,要解決此問題,您可以查看PyQt4檔案,Qt for Python檔案或原始Qt檔案,
要在PyQt的視窗或表單上排列小部件,可以使用以下技術:
在小部件上使用
.resize()和.move()來提供絕對大小和位置,重新實作
.resizeEvent()并動態計算小部件的大小和位置,使用布局管理器,讓他們為您做所有的計算和辛苦的作業,
這些技術通常對應于上一節中介紹的用于布局GUI的三種不同方法,
再說一次,動態計算尺寸和位置可能是個好方法,但是大多數時候,使用布局管理器會更好,在PyQt中,布局管理器是提供所需功能以自動管理布局中小部件的大小,位置和調整大小行為的類,
使用布局管理器,您可以自動在任何母部件、容器、小部件內排列子部件,使用布局管理器將確保您充分利用GUI上的可用空間,并確保當用戶調整視窗大小時,應用程式仍然可用,
布局管理器充當小部件和其他布局的容器時,要將小部件添加到布局管理器,請在當前布局上呼叫.addWidget(),要將布局添加到另一個布局,請在當前布局上呼叫.addLayout(),您將在“嵌套布局以構建復雜的GUI”一節中更深入地了解嵌套布局,
將所有必需的小部件添加到布局管理器后,即可使用.setLayout()在給定的小部件上設定布局管理器,您可以在QWidget的任何子類(包括視窗或表單)上設定布局管理器,
注意:QMainWindow是一個PyQt類,可用于創建main widow–style applications.,此類具有其自己的內置布局管理器,因此,如果您使用的是QMainWindow,則通常不需要在主視窗物件上設定布局管理器,
布局中的所有視窗小部件都會自動設定為安裝布局的視窗小部件的子級,而不是布局本身,這是因為視窗小部件只能將其他視窗小部件(而不是布局)作為其父級,
PyQt的布局管理器提供了一些很酷的功能,可以使您在創建美觀的GUI應用程式時更加輕松:
處理小部件的大小和位置,無需任何計算
當用戶調整基礎視窗的大小時,處理視窗小部件的大小調整和重新定位
調整標簽大小以更好地支持國際化
為多平臺應用程式提供本機視窗布局
從長遠來看,使用布局管理器還將極大地提高您的生產率并改善代碼的可維護性,
PyQt提供了四個通用布局管理器類:
QHBoxLayout在水平框中排列小部件,QVBoxLayout在垂直框中排列小部件,QGridLayout將小部件排列在網格中,QFormLayout將小部件安排在兩列中,
在接下來的幾節中,您將學習如何使用這些通用布局管理器的基礎知識,
使用通用布局管理器
使用PyQt創建GUI應用程式時,通常會使用上一節末尾看到的四種通用布局中的一種或多種方法,來將視窗小部件布置在視窗和表單上,
在接下來的幾節中,您將在一些示例的幫助下學習如何創建和使用四個通用布局管理器,
構建水平布局:QHBoxLayout
Box layout managers從父布局或視窗小部件獲得的空間被分成多個盒子或單元格,然后使布局中的每個視窗小部件填充一個盒子,
QHBoxLayout是PyQt中兩個可用的框布局之一,這個布局管理器允許您水平排列小部件,一個接一個,這些小部件從左到右添加到布局中,這意味著您首先在代碼中添加的小部件將是布局中最左側的小部件,
要將小部件添加到QHBoxLayout物件,請在布局物件上呼叫.addWidget(widget,stretch,alignment),此方法接受一個必需引數和兩個可選引數:
widget是必填引數,用于保存要添加到布局的特定widget,Stretch是一個可選引數,其中包含一個整數,該整數表示要應用于小部件的拉伸因子,具有較高拉伸因子的小部件在調整視窗大小時會增長更多,默認為0,這表示未分配視窗小部件拉伸因子,alignment是一個可選引數,其中包含水平和垂直標志,您可以組合這些標志,以在其包含的單元格內產生所需的小部件對齊方式,默認為0,這意味著小部件將填充整個單元格,
下面是一個小型應用程式,顯示了如何使用QHBoxLayout創建水平布局,在此示例中,您將使用QPushButton物件根據將小部件添加到代碼中的順序更好地可視化每個小部件在布局中的放置位置:
import sys
from PyQt5.QtWidgets import (
QApplication,
QHBoxLayout,
QPushButton,
QWidget,
)
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QHBoxLayout Example")
# Create a QHBoxLayout instance
layout = QHBoxLayout()
# Add widgets to the layout
layout.addWidget(QPushButton("Left-Most"))
layout.addWidget(QPushButton("Center"), 1)
layout.addWidget(QPushButton("Right-Most"), 2)
# Set the layout on the application's window
self.setLayout(layout)
print(self.children())
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
在第15行上,創建一個稱為layout的QHBoxLayout物件,在第17至19行,使用.addWidget()將三個按鈕添加到布局中,請注意,您分別在“居中”和“最右”按鈕中將1和2傳遞給了stretch引數,在第21行,使用.setLayout()將布局設定為視窗的頂級布局,
如果您運行此應用程式,則會在螢屏上看到以下視窗:
該視窗包含三個水平排列的按鈕,請注意,“最左鍵”按鈕對應于您在代碼中添加的第一個按鈕,因此,按鈕的顯示順序與您在代碼中添加按鈕的順序(從左到右)(從上到下)相同,
“居中”和“最右邊”按鈕具有不同的拉伸系數,因此在調整視窗大小時,它們會按比例縮放,
此外,布局中的所有按鈕和布局本身都設定為Window的子級,這是由布局物件自動完成的,該布局物件在每個小部件上內部呼叫.setParent(),在第17行上對print()的呼叫將在您的終端上列印Window的子代串列,以證明此行為,
構建垂直布局:QVBoxLayout
QVBoxLayout垂直排列小部件,一個在另一個下方,您可以使用此類創建垂直布局,并從上到下排列視窗小部件,由于QVBoxLayout是另一個框布局,因此其.addWidget()方法的作業方式與QHBoxLayout中的相同,
下面是一個PyQt應用程式,它顯示了如何創建和使用QVBoxLayout物件在GUI中創建小部件的垂直排列:
import sys
from PyQt5.QtWidgets import (
QApplication,
QPushButton,
QVBoxLayout,
QWidget,
)
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QVBoxLayout Example")
self.resize(270, 110)
# Create a QVBoxLayout instance
layout = QVBoxLayout()
# Add widgets to the layout
layout.addWidget(QPushButton("Top"))
layout.addWidget(QPushButton("Center"))
layout.addWidget(QPushButton("Bottom"))
# Set the layout on the application's window
self.setLayout(layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
在第16行上,您將創建QVBoxLayout的實體,在第18至20行上,將三個按鈕添加到布局中,最后,將布局設定為視窗的頂層布局,
如果您運行此應用程式,則將顯示以下視窗:
您的視窗顯示了三個垂直排列的按鈕,一個在另一個按鈕下面,這些按鈕的顯示順序(從上到下)與您在代碼中添加的順序(從上到下)相同,
在網格中排列小部件:QGridLayout
您可以使用QGridLayout將小部件排列在行和列的網格中,每個小部件將在網格中具有相對位置,要定義小部件的位置或網格中的單元格,請使用表格(行,列)的一對坐標,這些坐標應該是從零開始的整數,
QGridLayout占用其父級的可用空間,將其劃分為行和列,然后將每個小部件放置在其自己的單元格或框中,QGridLayout根據小部件的數量及其坐標自動計算出最終布局將包含多少行和多少列,如果您不將小部件添加到給定的單元格,則QGridLayout將使該單元格為空,
要將小部件添加到網格布局,請在布局上呼叫.addWidget(),此方法有兩個不同的多載實作:
addWidget(widget, row, column, alignment)將widget添加到(row, column)的單元格中,addWidget(widget,fromRow,fromColumn,rowSpan,columnSpan,alignment)將widget添加到單元格中,跨越多行,多列或兩者,
第一個實作采用以下引數:
widget是必填引數,用于保存您需要添加到布局的特定小部件,row是必填引數,其中包含一個整數,該整數表示網格中行的坐標,column是必填引數,其中包含一個整數,該整數表示網格中列的坐標,alignment是一個可選引數,用于保存小部件在其包含的單元格內的對齊方式,默認為0,這意味著小部件將填充整個單元格,
這是一個如何使用QGridLayout創建小部件網格的示例:
import sys
from PyQt5.QtWidgets import (
QApplication,
QGridLayout,
QPushButton,
QWidget,
)
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QGridLayout Example")
# Create a QGridLayout instance
layout = QGridLayout()
# Add widgets to the layout
layout.addWidget(QPushButton("Button at (0, 0)"), 0, 0)
layout.addWidget(QPushButton("Button at (0, 1)"), 0, 1)
layout.addWidget(QPushButton("Button at (0, 2)"), 0, 2)
layout.addWidget(QPushButton("Button at (1, 0)"), 1, 0)
layout.addWidget(QPushButton("Button at (1, 1)"), 1, 1)
layout.addWidget(QPushButton("Button at (1, 2)"), 1, 2)
layout.addWidget(QPushButton("Button at (2, 0)"), 2, 0)
layout.addWidget(QPushButton("Button at (2, 1)"), 2, 1)
layout.addWidget(QPushButton("Button at (2, 2)"), 2, 2)
# Set the layout on the application's window
self.setLayout(layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
在第15行上,創建QGridLayout物件,然后,在第17至25行上,使用.addWidget()將小部件添加到布局中,要查看沒有分配小部件的網格布局如何管理單元,請注釋掉其中的一行或多行,然后再次運行應用程式,
如果您從命令列運行此代碼,則將獲得如下所示的視窗:
QGridLayout物件中的每個小部件都占據由您在.addWidget()中提供的一對坐標定義的單元格,每個按鈕上的文字均反映了這些坐標,坐標是從零開始的,因此第一個單元格位于(0,0),
在.addWidget()的第二種實作中,widget和alignment引數保持不變,并且您還有四個其他引數可用于將小部件放置在多行或多列中:
fromRow賦值一個整數,該整數表示小部件將在其中開始的行,fromColumn賦值一個整數,該整數表示小部件將在其中開始的列,rowSpan賦值一個整數,該整數表示視窗小部件將在網格中占據的行數,columnSpan賦值一個整數,該整數表示視窗小部件將在網格中占據的列數,
這是一個顯示.addWidget()變體如何作業的應用程式:
import sys
from PyQt5.QtWidgets import (
QApplication,
QGridLayout,
QPushButton,
QWidget,
)
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QGridLayout Example")
# Create a QGridLayout instance
layout = QGridLayout()
# Add widgets to the layout
layout.addWidget(QPushButton("Button at (0, 0)"), 0, 0)
layout.addWidget(QPushButton("Button at (0, 1)"), 0, 1)
layout.addWidget(QPushButton("Button Spans two Cols"), 1, 0, 1, 2)
# Set the layout on the application's window
self.setLayout(layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
在第19行,使用.addWidget()的第二種實作來添加一個占用網格中兩列的按鈕,該按鈕從第二行(fromRow = 1)和第一列(fromColumn = 0)開始,最后,該按鈕占據一行(rowSpan = 1)和兩列(columnSpan = 2),
如果您運行此應用程式,則會在螢屏上看到以下視窗:
在這種布局中,您可以使一個小部件占用多個單元格,就像使用“跨越兩個列”的按鈕一樣,
在下篇中,我們將看到:
如何快速創建表單
嵌套布局以構建復雜的GUI
使用多頁布局和小部件
布置應用程式的主視窗
布置應用程式的對話框
在PyQt布局中管理輸入框
更多閱讀
有人在代碼里下毒!慎用 pip install 命令
pip 20.3 新版本發布!即將拋棄 Python 2.x
5 分鐘掌握 Python 中的 Hook 鉤子函式
特別推薦
程式員摸魚指南
為你精選的硅谷極客資訊,
來自FLAG巨頭開發者、技術、創投一手訊息
點擊下方閱讀原文加入社區會員
點贊鼓勵一下
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/232575.html
標籤:python
