布局管理是GUI编程中的一个重要方面。布局管理是一种如何在应用窗口上防止组件的一种方法。但用 qtdesigner + eric6 会是更方便选择。
我们可以通过两种基础方式来管理布局。我们可以使用绝对定位和布局类。
一、绝对定位
程序指定了组件的位置并且每个组件的大小用像素作为单位来丈量。当你使用了绝对定位,我们需要知道下面的几点限制:
- 如果我们改变了窗口大小,组件的位置和大小并不会发生改变。
- 在不同平台上,应用的外观可能不同
- 改变我们应用中的字体的话可能会把应用弄得一团糟。
- 如果我们决定改变我们的布局,我们必须完全重写我们的布局,这样非常乏味和浪费时间。
import sys
from PyQt5.QtWidgets import QWidget, QLabel, QApplication
class Example(QWidget):
def __init__(self):
super().__init__()
self.my_UI()
def my_UI(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, 300, 250)
self.setWindowTitle('Absolute')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
我们使用move()方法来定位我们的组件。在上面的例子中我们使用move()方法定位了一些标签组件。在使用move()方法时,我们给move()方法提供了x和y坐标作为参数。move()使用的坐标系统是从左上角开始计算的。x值从左到右增长。y值从上到下增长。
二、箱布局
布局管理器的布局管理类非常灵活,实用。它是将组件定位在窗口上的首选方式。QHBoxLayout和QVBoxLayout是两个基础布局管理类,他们水平或垂直的线性排列组件。想象一下我们需要在右下角排列两个按钮。为了使用箱布局,我们将使用一个水平箱布局和垂直箱布局来实现。同样为了使用一些必要的空白,我们将添加一些拉伸因子。
import sys
from PyQt5.QtWidgets import (QWidget, QPushButton,
QHBoxLayout, QVBoxLayout, QApplication)
#水平布局 垂直布局
class Example(QWidget):
def __init__(self):
super().__init__()
self.my_UI()
def my_UI(self):
okButton = QPushButton("确定")
cancelButton = QPushButton("取消")
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, 300, 150)
self.setWindowTitle('Buttons')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
三、网格布局
最常用的布局类是网格布局。这个布局使用行了列分割空间。要创建一个网格布局,我们需要使用QGridLayout类。
import sys
from PyQt5.QtWidgets import (QWidget, QGridLayout,
QPushButton, QApplication)
class Example(QWidget):
def __init__(self):
super().__init__()
self.my_UI()
def my_UI(self):
grid = QGridLayout() #实例化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) #创建出按钮组件,并使用addWidget()方法向布局中添加按钮
self.move(300, 150)
self.setWindowTitle('计算器')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
在我们的例子中,我们创建了一个全是按钮的网格布局。
四、文本审阅窗口示例
在网格中,组件可以跨多列或多行。在这个例子中,我们对它进行一下说明。
import sys
from PyQt5.QtWidgets import (QWidget, QLabel, QLineEdit,
QTextEdit, QGridLayout, QApplication)
class Example(QWidget):
def __init__(self):
super().__init__()
self.my_UI()
def my_UI(self):
title = QLabel('Title')
author = QLabel('Author')
review = QLabel('Review')
titleEdit = QLineEdit()
authorEdit = QLineEdit()
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)
#向网格布局中增加一个组件,可以提供组件的跨行和跨列参数
#在这个例子中,我们让reviewEdit组件跨了5行。
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布局。