佈局管理
在一個GUI程序裏,佈局是一個很重要的方面。佈局就是如何管理應用中的元素和窗口。有兩種方式可以搞定:絕對定位和PyQt5的layout類
絕對定位
每個程序都是以像素爲單位區分元素的位置,衡量元素的大小。所以我們完全可以使用絕對定位搞定每個元素和窗口的位置。但是這也有侷限性:
- 元素不會隨着我們更改窗口的位置和大小而變化。
- 不能適用於不同的平臺和不同分辨率的顯示器
- 更改應用字體大小會破壞佈局
- 如果我們決定重構這個應用,需要全部計算一下每個元素的位置和大小
下面這個就是絕對定位的應用
""""
brief:絕對定位
程序指定每個控件的位置和大小(以像素爲單位)。
絕對定位有以下限制:
如果我們調整窗口,控件的大小和位置不會改變
在各種平臺上應用程序看起來會不一樣
如果改變字體,我們的應用程序的佈局就會改變
如果我們決定改變我們的佈局,我們必須完全重做我們的佈局
author:chenyijun
date:2020-01-26
"""
import sys
from PyQt5.QtWidgets import QWidget, QLabel, QApplication
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
label1 = QLabel("Zetcode", self)
label1.move(15, 10)
label2 = QLabel("Tutorials", self)
label2.move(35, 40)
label3 = QLabel("for programmers", self)
label3.move(55, 70)
self.setGeometry(300, 300, 350, 150)
self.setWindowTitle("Absolute")
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
我們使用move()方法定位了每一個元素,使用x、y座標。x、y座標的原點是程序的左上角。
lbl1 = QLabel('Zetcode', self) lbl1.move(15, 10)
這個元素的左上角就在這個程序的左上角開始的(15, 10)的位置。
程序展示:
盒佈局
使用盒佈局能讓程序具有更強的適應性。這個纔是佈局一個應用的更合適的方式。QHBoxLayout和QVBoxLayout是基本的佈局類,分別是水平佈局和垂直佈局。
如果我們需要把兩個按鈕放在程序的右下角,創建這樣的佈局,我們只需要一個水平佈局加一個垂直佈局的盒子就可以了。再用彈性佈局增加一點間隙。
""""
brief:框佈局 Boxlayout
我們使用QHBoxLayout和QVBoxLayout,來分別創建橫向佈局和縱向佈局。
author:chenyijun
date:2020-01-26
"""
import sys
from PyQt5.QtWidgets import (QWidget, QPushButton, QHBoxLayout, QVBoxLayout,
QApplication)
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
okButton = QPushButton("OK")
cancelButton = QPushButton("Cancel")
hbox = QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(okButton)
hbox.addWidget(cancelButton)
vbox = QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)
self.setLayout(vbox)
self.setGeometry(300, 300, 350, 150)
self.setWindowTitle("Buttons")
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = Example();
sys.exit(app.exec_())
上面的例子完成了在應用的右下角放了兩個按鈕的需求。當改變窗口大小的時候,它們能依然保持在相對的位置。我們同時使用了QHBoxLayout和QVBoxLayout。
okButton = QPushButton("OK") cancelButton = QPushButton("Cancel")
這是創建了兩個按鈕。
hbox = QHBoxLayout() hbox.addStretch(1) hbox.addWidget(okButton) hbox.addWidget(cancelButton)
創建一個水平佈局,增加兩個按鈕和彈性空間。stretch函數在兩個按鈕前面增加了一些彈性空間。下一步我們把這些元素放在應用的右下角。
vbox = QVBoxLayout() vbox.addStretch(1) vbox.addLayout(hbox)
爲了佈局需要,我們把這個水平佈局放到了一個垂直佈局盒裏面。彈性元素會把所有的元素一起都放置在應用的右下角。
self.setLayout(vbox)
最後,我們就得到了我們想要的佈局。
程序預覽:
柵格佈局
最常用的還是柵格佈局了。這種佈局是把窗口分爲行和列。創建和使用柵格佈局,需要使用QGridLayout模塊。
""""
brief:表格佈局 QGridLayout
表格佈局將空間劃分爲行和列。我們使用QGridLayout類創建一個網格佈局。
author:chenyijun
date:2020-01-26
"""
import sys
from PyQt5.QtWidgets import (QWidget, QGridLayout, QPushButton, QApplication)
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
grid = QGridLayout()
self.setLayout(grid)
names = ["Cls", "Bck", "", "Close",
"7", "8", "9", "/",
"4", "5", "6", "*",
"1", "2", "3", "-",
"0", ".", "=", "+"]
positions = [(i, j) for i in range(5) for j in range(4)]
for position, name in zip(positions, names):
if name == "":
continue
button = QPushButton(name)
grid.addWidget(button, *position)
self.move(350, 150)
self.setWindowTitle("Calculator")
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = Example();
sys.exit(app.exec_())
這個例子裏,我們創建了柵格化的按鈕。
grid = QGridLayout() self.setLayout(grid)
創建一個QGridLayout實例,並把它放到程序窗口裏。
names = ['Cls', 'Bck', '', 'Close', '7', '8', '9', '/', '4', '5', '6', '*', '1', '2', '3', '-', '0', '.', '=', '+']
這是我們將要使用的按鈕的名稱。
positions = [(i,j) for i in range(5) for j in range(4)]
創建按鈕位置列表。
for position, name in zip(positions, names): if name == '': continue button = QPushButton(name) grid.addWidget(button, *position)
創建按鈕,並使用addWidget()方法把按鈕放到佈局裏面。
程序預覽:
製作提交反饋信息的佈局
組件能跨列和跨行展示,這個例子裏,我們就試試這個功能。
""""
brief:評論的例子
控件可以在網格中跨越多個行或列。在下一個示例中,我們說明了這一點。
author:chenyijun
date:2020-01-26
"""
import sys
from PyQt5.QtWidgets import (QWidget, QLabel, QLineEdit,
QTextEdit, QGridLayout, QApplication)
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
title = QLabel("Title")
author = QLabel("Author")
review = QLabel("Review")
titleEdit = QLineEdit()
authorEdit = QTextEdit()
reviewEdit = QTextEdit()
grid = QGridLayout()
grid.setSpacing(10)
grid.addWidget(title, 1, 0)
grid.addWidget(titleEdit, 1, 1)
grid.addWidget(author, 2, 0)
grid.addWidget(authorEdit, 2, 1)
grid.addWidget(review, 3, 0)
grid.addWidget(reviewEdit, 3, 1, 5, 1)
self.setLayout(grid)
self.setGeometry(300, 300, 350, 300)
self.setWindowTitle("Review")
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
我們創建了一個有三個標籤的窗口。兩個行編輯和一個文版編輯,這是用QGridLayout模塊搞定的。
grid = QGridLayout() grid.setSpacing(10)
創建標籤之間的空間。
grid.addWidget(reviewEdit, 3, 1, 5, 1)
我們可以指定組件的跨行和跨列的大小。這裏我們指定這個元素跨5行顯示。
程序預覽:
參考:
https://maicss.gitbooks.io/pyqt5/