原文:
布局管理是GUI编程中的重要部分。布局管理是如何将控件放置于窗体上的技术,它的实现有两种基本方式:绝对布局与layout类。
##绝对布局
程序员要指定每个控件的像素位置与大小。在使用绝对布局时要知道它的局限:
- 控件的尺寸与位置不会随着窗体尺寸的调整而变化
- 程序在不同平台上可能会有不同的外观
- 改变程序的字体可能会破坏布局
- 如果想改变布局,只能重做,这很无聊而且很费时
下面的示例中以绝对坐标来放置控件。
#!/usr/bin/python3# -*- coding: utf-8 -*-"""ZetCode PyQt5 tutorial This example shows three labels on a windowusing absolute positioning. author: Jan Bodnarwebsite: zetcode.com last edited: January 2015"""import sysfrom PyQt5.QtWidgets import QWidget, QLabel, QApplicationclass 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()
方法来放置控件。在例子中我们通过设置x、y坐标来放置label。坐标系统的原点位于窗体左上角。x轴从左到右增长,y轴从上到下增长。
lbl1 = QLabel('Zetcode', self)lbl1.move(15, 10)
label控件位于x=15,y=10的坐标上。
Box layout
布局类提供的布局管理具有更好的灵活性与实用性,它是在窗体上放置控件的首选方式。QHBoxLayout
与QVBoxLayout
是水平与垂直放置控件的两个基本布局类。
假如要在右下角放置两个按钮,我们要借助于HBoxLayout与VBoxLayout,并设置stretch factor(伸展系数)
来创建所需的空白空间。
#!/usr/bin/python3# -*- coding: utf-8 -*-"""ZetCode PyQt5 tutorial In this example, we position two pushbuttons in the bottom-right corner of the window. author: Jan Bodnarwebsite: zetcode.com last edited: January 2015"""import sysfrom 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_())
这个示例在窗体的右下角放置了两个按钮。当调整窗体尺寸时它们的位置不会改变。我们同时用到了QHBoxLayout
与QVBoxLayout
。
okButton = QPushButton("OK")cancelButton = QPushButton("Cancel")
这里创建了两个按钮
hbox = QHBoxLayout()hbox.addStretch(1)hbox.addWidget(okButton)hbox.addWidget(cancelButton)
我们创建了一个水平boxlayout并添加了一个伸展系数和两个按钮。stretch
方法会在两按钮前面添加一个伸展空间,从而将按钮挤到窗体的右侧。
vbox = QVBoxLayout()vbox.addStretch(1)vbox.addLayout(hbox)
通过将水平布局置于垂直布局内来得到我们需要的布局。垂直布局的伸展系数会将按钮挤到窗体底部。
self.setLayout(vbox)
最后将vbox设为窗体的主布局。
QGridLayout
网格布局是最常用的布局。它会按行列对空间进行切分。我们使用类QGridLayout
创建网格布局。
#!/usr/bin/python3# -*- coding: utf-8 -*-"""ZetCode PyQt5 tutorial In this example, we create a skeletonof a calculator using a QGridLayout.author: Jan Bodnarwebsite: zetcode.com last edited: January 2015"""import sysfrom 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_())
在这个例子中我们创建填满整个网格的按钮。
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()
方法将创建的按钮添加到布局中。
一个简单的评论窗体
控件可以在布局中跨行或跨列。正如下面的例子所展示的。
#!/usr/bin/python3# -*- coding: utf-8 -*-"""ZetCode PyQt5 tutorial In this example, we create a bitmore complicated window layout usingthe QGridLayout manager. author: Jan Bodnarwebsite: zetcode.com last edited: January 2015"""import sysfrom 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_())
我们创建了一个带有三个Label、两个LineEdit和一个TextEdit的窗体。采用了QGridLayout
布局。
grid = QGridLayout()grid.setSpacing(10)
我们创建了一个网格布局并为它设置了控件间距。
grid.addWidget(reviewEdit, 3, 1, 5, 1)
在添加控件的时候我们可以设置控件跨行或跨列。在例子中我们将reviewEdit控件跨越5行。
这部分教程主要讲解了布局管理。