布局管理器
通过布局管理器在应用窗口中放置控件。我们可以用绝对位置或用各种layout类放置控件。用布局管理器管理布局是组织控件的最佳方式。
Absolute positioning
定义:程序中指定每个控件的位置和大小
用这种放置,有如下限制:
- 当调整应用窗口大小时,控件的大小和位置不会改变
- 应用在不同平台表现可能不同
- 应用中改变字体大小可能破坏应用布局
- 如果要想改变布局,必须彻底重做,这是乏味和耗时的
以下是用absolute coordinates方式定位控件的例子。
#This example shows three labels on a window using absolute positioning.
import sys
from PyQt5.QtWidgets import QWidget, QLabel, QApplication
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
lbl1 = QLabel('Zetcode', self)
lbl1.move(15, 10)
lbl2 = QLabel('tutorials', self)
lbl2.move(35, 40)
lbl3 = QLabel('for programmers', self)
lbl3.move(55, 70)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Absolute')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
必须使用move()方法定位控件。例子中是一些label,通过给出x,y坐标定位他们,坐标的原点位于左上角。x轴正方向是从左往右,y轴正方向是从上往下。
lb11 = QLabel('Zetcode', self)
lb11.move(15, 10)
该label控件定位在(15,10)坐标点
Box layout
QHBoxLayout和QVBoxLayout是布局基类,可以水平、垂直排列控件(类似于android中的LinearLayout)。
假设要在右下角放置2个button。使用一个水平和一个垂直box来造,添加一个拉伸因子来造必要的空间。
#In this example, we position two push buttons in the bottom-right corner of the window.
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, 300, 150)
self.setWindowTitle('Buttons')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
在窗口的右下角放置了2个按键。即使应用改变窗口大小和位置,他们的大小和位置也不会改变。
okButton = QPushButton("OK")
cancelButton = QPushButton("Cancel")
以上创建了2个button
hbox = QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(okButton)
hbox.addWidget(cancelButton)
以上创建了一个水平box和一个拉伸因子以及button。拉伸因子在2个按键的前面添加一个可伸缩的空间,导致将按键推到窗口的右侧。
vbox = QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)
水平的box layout被放置到垂直的box layout,垂直box中的拉伸因子会将水平的box推到窗口的下面。
self.setLayout(vbox)
最后设置应用窗口的主布局。
QGridLayout
QGridLayout是最普遍的布局类,它将空间分割成行列。
#we create a skeleton of a calculator using QGridLayout.
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(300, 150)
self.setWindowTitle('Calculator')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
上例中创建了button网格
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()方法将按键添加到QGridLayout中
Review example
控件可以跨越网格的多行多列,下面举例说明。
#we create a bit more complicated window layout using the QGridLayout manager.
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 = 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)
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_())
以上创建一个包含3个label、2个line edit、1个text edit 控件的窗口,布局使用QGridLayout。
grid = QGridLayout()
grid.setSpacing(10)
创建一个网格布局并设置控件间的间隔
grid.addWidget(reviewEdit, 3, 1, 5, 1)
如果将控件添加到网格中,需要提供控件的行列跨度,例子中设置reviewEdit这个控件跨度5行。