(本系列中所有代码在windows7 64位[]/Python 3.4.3 32bit/PyQt GPL v5.5 for Python v3.4 (x32)/eric6-6.0.8下测试通过.)
原本地址:http://zetcode.com/gui/pyqt5/
================================================================================
GUI程序的重要一个方面就是布局管理.布局管理是我们如何将部件放到程序窗口内.这有两种方法.即绝对定位和布局类.
绝对定位
程序员定位每个部件的位置和大小到像素级.当你使用绝对定位时,我们需要明白以下的限制:
如果我们改变一个窗口的大小时,一个部件的大小和定位不能更改.
程序可能在不同平台上看起来不一样.
在我们的程序内改变字体时可能会破坏布局
如果我们决定修改布局,我们必须全部重做我们的布局,那可是繁琐又费时的.
下面的例子是用绝对定位布局部件.
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_())
我们用mover()方法来定位我们的部件.在这个例子中部件是标签.我们定位他们的时候是用的坐标轴的x和y.最开始的坐标系统是在左上角.x是从左到右的,y是从上到下的.
lbl1 = QLabel('Zetcode', self) lbl1.move(15, 10)标签部件定位在x=15,y=10的位置.
图片:绝对定位
框布局
用布局类的布局管理有着更好的灵活性和实用性.它是更好的将部件放到一个窗口中的办法.QHBoxLayout和QVBoxLayout是基本的布局类,它会让部件们水平和垂直的对齐是.
想象一下,我们想把两个按钮放到右下角.要创建一个这样的布局,我们要用到一个水平和一个垂直框.为了创建必要的空间,我们要添加一下伸缩因子.
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_())
例子中我们在窗口的右下角放置了两个按钮.当我们调整程序窗口的大小时,它们的位置不变.我们用了一个HBoxLayout和一个QVBoxLayout.
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)最终,我们设置窗口的主布局.
图片:按钮
QGridLayout(网格布局)
最常用的布局类是网格布局.这个布局将空间分隔为行和列.要创建一个网络布局,我们会用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_())
在这个例子中,我们创建了网格按钮.要填补一个空位,我们就添加一个QLabel部件.
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()方法被添加到布局中.
图片:计算器
复审例子
部件在网格中可以被分成多行多列.在下一个例子中我们会演示.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_())
我们创建一个带有三个标签的窗口,两个行行编辑器和一个文件编辑器部件.布局是通过QGridLayout完成的.
grid = QGridLayout() grid.setSpacing(10)我们创建一个网格布局并设置部件之间的间距.
grid.addWidget(reviewEdit, 3, 1, 5, 1)如果我们添加一个部件到网格,我们可以提供部件的行宽和列宽.在这个例子中,我们用reviewEdit把部件分成5行.
图片:复审