PyQt5系列教程(6):布局

上期我們介紹了PyQt5的事件與信號,主要涉及到了以下幾個知識點:

  • 信號與槽連接
  • 事件處理重寫
  • 事件發送者
  • 發出自定義信號

今天我們主要講解一下布局的知識

----------------------------------------------------華麗的分割線------------------------------------------------------------

首先我們來看看採用布局和沒有採用布局的對比效果

這是沒有採用布局的

這是採用布局的

通過對比我們知道採用了布局之後能夠讓我們的程序在使用上更加美觀,不會隨著窗體的大小發生改變而改變,符合我們的使用習慣。

----------------------------------------------------華麗的分割線------------------------------------------------------------

絕對位置

程序員以像素為單位指定每個小部件的位置和大小。 當您使用絕對定位時,我們必須了解以下限制:

  1. 如果我們調整窗口大小,則小部件的大小和位置不會改變
  2. 各種平台上的應用可能會有所不同
  3. 在我們的應用程序中更改字體可能會損壞布局
  4. 如果我們決定改變我們的布局,我們必須徹底重做布局,這很浪費時間

下面這個例子我們將小部件置於絕對坐標中

#coding = utf-8nnimport sysnfrom PyQt5.QtWidgets import (QWidget, QPushButton, QApplication)nnclass Example(QWidget):n def __init__(self):n super().__init__()n self.Init_UI()n def Init_UI(self):n self.setGeometry(300,300,400,300)n self.setWindowTitle(學點編程吧)nn bt1 = QPushButton(剪刀,self)n bt1.move(50,250)nn bt2 = QPushButton(石頭,self)n bt2.move(150,250)nn bt3 = QPushButton(,self)n bt3.move(250,250)n self.show()nnif __name__ == __main__:n app = QApplication(sys.argv)n ex = Example()n app.exit(app.exec_())n

執行效果如下:

我們使用move()方法來定位我們的小部件。 在我們的例子中,這些是按鈕。 我們通過提供x和y坐標來定位它們。 坐標系的開始位於左上角。 x值從左到右增長。 y值不變。

----------------------------------------------------華麗的分割線------------------------------------------------------------

箱式布局

QHBoxLayout和QVBoxLayout是基本的布局類,它們在水平和垂直方向上排列小部件。

想像一下,我們想在右下角放置三個按鈕。 要創建這樣一個布局,我們使用一個水平和一個垂直方框。 為了創建必要的空間,我們添加一個拉伸因子。

#coding = utf-8nnimport sysnfrom PyQt5.QtWidgets import (QWidget, QPushButton, QApplication, QHBoxLayout, QVBoxLayout)nnclass Example(QWidget):n def __init__(self):n super().__init__()n self.Init_UI()n def Init_UI(self):n self.setGeometry(300,300,400,300)n self.setWindowTitle(學點編程吧)nn bt1 = QPushButton(剪刀, self)n bt2 = QPushButton(石頭, self)n bt3 = QPushButton(, self)nn hbox = QHBoxLayout()n hbox.addStretch(1)n hbox.addWidget(bt1)n hbox.addWidget(bt2)n hbox.addWidget(bt3)nn vbox = QVBoxLayout()n vbox.addStretch(1)n vbox.addLayout(hbox)nn self.setLayout(vbox)nn self.show()nif __name__ == __main__:n app = QApplication(sys.argv)n ex = Example()n app.exit(app.exec_())n

執行效果如下:

該示例在窗口的右下角放置了三個按鈕。 當我們調整應用程序窗口大小時,它們會留在那裡,我們同時使用一個HBoxLayout和一個QVBoxLayout。

bt1 = QPushButton(剪刀, self)nbt2 = QPushButton(石頭, self)nbt3 = QPushButton(, self)n

我們新建三個按鈕

hbox = QHBoxLayout()nhbox.addStretch(1)nhbox.addWidget(bt1)nhbox.addWidget(bt2)nhbox.addWidget(bt3)n

我們創建一個水平框布局,並添加一個拉伸因子和三個按鈕。這個拉伸在三個按鈕之前增加了一個可伸縮的空間。這將把它們推到窗口的右邊。

vbox = QVBoxLayout()nvbox.addStretch(1)nvbox.addLayout(hbox)n

水平布局放置在垂直布局中。垂直框中的拉伸因子將按鈕的水平框推到窗口的底部。

self.setLayout(vbox)n

最後,我們設置窗口的主要布局。

細心的同學可能會發現:addStretch(1),這個函數如何確定其中的參數大小,這裡簡單的說一下。

addStretch函數的作用是在布局器中增加一個伸縮量,裡面的參數表示QSpacerItem的個數,默認值為零,會將你放在layout中的空間壓縮成默認的大小。例如用addStretch函數實現將QHBoxLayout的布局器的空白空間分配。

#coding = utf-8nnimport sysnfrom PyQt5.QtWidgets import (QWidget, QPushButton, QApplication, QHBoxLayout)nnclass Example(QWidget):n def __init__(self):n super().__init__()n self.Init_UI()n def Init_UI(self):n self.setGeometry(300,300,400,300)n self.setWindowTitle(學點編程吧)nn bt1 = QPushButton(剪刀, self)n bt2 = QPushButton(石頭, self)n bt3 = QPushButton(, self)nn hbox = QHBoxLayout()n hbox.addStretch(1) #增加伸縮量n hbox.addWidget(bt1)n hbox.addStretch(1)#增加伸縮量n hbox.addWidget(bt2)n hbox.addStretch(1)#增加伸縮量n hbox.addWidget(bt3)n hbox.addStretch(6)#增加伸縮量nn self.setLayout(hbox)nn self.show()nif __name__ == __main__:n app = QApplication(sys.argv)n ex = Example()n app.exit(app.exec_())n

執行效果如下:

其中四個addStretch()函數用於在button按鈕間增加伸縮量,伸縮量的比例為1:1:1:6,意思就是將button以外的空白地方按設定的比例等分為9份並按照設定的順序放入布局器中。

-------------------------------------------------------華麗的分割線---------------------------------------------------------

格柵布局,也被稱作網格布局(多行多列)

柵格布局將位於其中的窗口部件放入一個網狀的柵格之中。QGridLayout需要將提供給它的空間劃分成的行和列,並把每個窗口部件插入並管理到正確的單元格。

柵格布局是這樣工作的:它計算了位於其中的空間,然後將它們合理的劃分成若干個行(row)和列(column),並把每個由它管理的窗口部件放置在合適的單元之中,這裡所指的單元(cell)即是指由行和列交叉所劃分出來的空間。

坐標分布是這樣的:

下面這個例子就是採用格柵布局製作的一個計算器界面,當然在功能上按下按鈕只是能顯示而已,不能進行具體的計算,後期我們會製作一個完整的計算器。

#coding = utf-8nnimport sysnfrom PyQt5.QtWidgets import (QWidget, QPushButton, QApplication, QGridLayout, QLCDNumber)nnclass Example(QWidget):n def __init__(self):n super().__init__()n self.Init_UI()nn def Init_UI(self):n grid = QGridLayout()n self.setLayout(grid)nn self.setGeometry(300,300,400,300)n self.setWindowTitle(學點編程吧-計算器)nn self.lcd = QLCDNumber()n grid.addWidget(self.lcd,0,0,3,0)n grid.setSpacing(10)nn names = [Cls, Bc, , Close,n 7, 8, 9, /,n 4, 5, 6, *,n 1, 2, 3, -,n 0, ., =, +]nn positions = [(i,j) for i in range(4,9) for j in range(4,8)]n for position, name in zip(positions, names):n if name == :n continuen button = QPushButton(name)n grid.addWidget(button, *position)n button.clicked.connect(self.Cli)nn self.show()nn def Cli(self):n sender = self.sender().text()n ls = [/, *, -, =, +]n if sender in ls:n self.lcd.display(A)n else:n self.lcd.display(sender)nnif __name__ == __main__:n app = QApplication(sys.argv)n ex = Example()n app.exit(app.exec_())n

執行的效果如下:

grid = QGridLayout()nself.setLayout(grid)n

創建QGridLayout的實例並將其設置為應用程序窗口的布局。

grid.addWidget(self.lcd,0,0,3,0)ngrid.setSpacing(10)n

如果我們向窗格添加窗口小部件,我們可以提供窗口小部件的行跨度和列跨度。 在我們的例子中,我們使QLCDNumber小部件跨越4行。同時我們創建一個網格布局並在窗口小部件之間設置間距。

names = [Cls, Bc, , Close,n 7, 8, 9, /,n 4, 5, 6, *,n 1, 2, 3, -, n 0, ., =, +]npositions = [(i,j) for i in range(4,9) for j in range(4,8)]n

我們創建了19個按鈕並指定了具體的坐標位置。

if name == : n continuenbutton = QPushButton(name)ngrid.addWidget(button, *position)nbutton.clicked.connect(self.Cli)n

使用addWidget()方法創建並添加到布局中的按鈕。同時當我們按下按鈕的時候調用self.Cli()方法

def Cli(self):n sender = self.sender().text()n ls = [/, *, -, =, +]n if sender in ls:n self.lcd.display(A)n else:n self.lcd.display(sender)n

當我們按下按鈕的時候我們會得到按鈕上顯示的名稱,如果是操作符則在LCD上顯示「A」(因為LCD的顯示功能有限),否則顯示我們按下的信息。

-------------------------------------------------------華麗的分割線---------------------------------------------------------

表單布局

QFormLayout管理輸入型控制項和關聯的標籤組成的那些Form表單。

QFormLayout是一個方便的布局類,其中的控制項以兩列的形式被布局在表單中。左列包括標籤,右列包含輸入控制項,例如:QLineEdit、QSpinBox、QTextEdit等。

下面這個例子就是說明表單布局是怎麼用的

#coding = utf-8nnimport sysnfrom PyQt5.QtWidgets import (QWidget, QPushButton, QApplication, QFormLayout, QLabel, QLineEdit, QTextEdit)nnclass Example(QWidget):n def __init__(self):n super().__init__()n self.Init_UI()n def Init_UI(self):n self.setGeometry(300,300,300,200)n self.setWindowTitle(學點編程吧)nn formlayout = QFormLayout()n nameLabel = QLabel("姓名")n nameLineEdit = QLineEdit("")n introductionLabel = QLabel("簡介")n introductionLineEdit = QTextEdit("")nn formlayout.addRow(nameLabel,nameLineEdit)n formlayout.addRow(introductionLabel,introductionLineEdit)n self.setLayout(formlayout)nn self.show()nif __name__ == __main__:n app = QApplication(sys.argv)n ex = Example()n app.exit(app.exec_())n

執行的效果如下:

formlayout = QFormLayout()n

創建一個表單布局

formlayout.addRow(nameLabel,nameLineEdit)nformlayout.addRow(introductionLabel,introductionLineEdit)n

向表單中增加一行,內容是我們定義的小部件。

-----------------------------------------------------華麗的分割線-----------------------------------------------------------

然後我們來看看Qt設計師裡面的布局操作

箱式布局-水平布局

箱式布局-垂直布局

柵格布局

表單布局

增加伸縮量

最後我們再簡單的談一下夥伴編輯。

什麼什麼?夥伴編輯,這貨是幹嘛用的?

意思就是設定label和lineEdit為夥伴關係後,label的Text為&t,那麼程序運行後,按住Alt+t就相當於單擊lineEdit。

用Qt設計師來看看如何實現,很簡單。

當我們按住Alt+n時,游標就到姓名那欄去了;當我們按住Alt+i時,游標就到簡介那欄去了。

-----------------------------------------------------華麗的分割線-----------------------------------------------------------

我們總結一下今天的內容:

  • 絕對位置
  • 箱式布局
  • 柵格布局
  • 表單布局
  • 編輯夥伴

ok,今天就到這裡,我們下期再約。

如果你想要本次教程中的相關源碼,請關注微信公眾號:學點編程吧,發送pyqt56,會自動得到相應的百度網盤下載鏈接。

推薦閱讀:

教程 | pyqt5極速打包界面軟體
PyQt5系列教程(15):單選按鈕
PyQt5系列教程(18):微調框1
PyQt5系列教程(21):標籤(QLabel)
PyQt5系列教程(17):跑馬燈(進度條的使用)

TAG:Python | Python教程 | PyQt |