• 布局管理
    • 绝对定位
    • 盒布局
    • 栅格布局
    • 制作提交反馈信息的布局

    布局管理

    在一个GUI程序里,布局是一个很重要的方面。布局就是如何管理应用中的元素和窗口。有两种方式可以搞定:绝对定位和PyQt5的layout类

    绝对定位

    每个程序都是以像素为单位区分元素的位置,衡量元素的大小。所以我们完全可以使用绝对定位搞定每个元素和窗口的位置。但是这也有局限性:

    • 元素不会随着我们更改窗口的位置和大小而变化。
    • 不能适用于不同的平台和不同分辨率的显示器
    • 更改应用字体大小会破坏布局
    • 如果我们决定重构这个应用,需要全部计算一下每个元素的位置和大小

    下面这个就是绝对定位的应用

    1. #!/usr/bin/python3
    2. # -*- coding: utf-8 -*-
    3. """
    4. ZetCode PyQt5 tutorial
    5. This example shows three labels on a window
    6. using absolute positioning.
    7. Author: Jan Bodnar
    8. Website: zetcode.com
    9. Last edited: August 2017
    10. """
    11. import sys
    12. from PyQt5.QtWidgets import QWidget, QLabel, QApplication
    13. class Example(QWidget):
    14. def __init__(self):
    15. super().__init__()
    16. self.initUI()
    17. def initUI(self):
    18. lbl1 = QLabel('Zetcode', self)
    19. lbl1.move(15, 10)
    20. lbl2 = QLabel('tutorials', self)
    21. lbl2.move(35, 40)
    22. lbl3 = QLabel('for programmers', self)
    23. lbl3.move(55, 70)
    24. self.setGeometry(300, 300, 250, 150)
    25. self.setWindowTitle('Absolute')
    26. self.show()
    27. if __name__ == '__main__':
    28. app = QApplication(sys.argv)
    29. ex = Example()
    30. sys.exit(app.exec_())

    我们使用move()方法定位了每一个元素,使用x、y坐标。x、y坐标的原点是程序的左上角。

    1. lbl1 = QLabel('Zetcode', self)
    2. lbl1.move(15, 10)

    这个元素的左上角就在这个程序的左上角开始的(15, 10)的位置。

    程序展示:

    Absolute positioning

    盒布局

    使用盒布局能让程序具有更强的适应性。这个才是布局一个应用的更合适的方式。QHBoxLayoutQVBoxLayout是基本的布局类,分别是水平布局和垂直布局。

    如果我们需要把两个按钮放在程序的右下角,创建这样的布局,我们只需要一个水平布局加一个垂直布局的盒子就可以了。再用弹性布局增加一点间隙。

    1. #!/usr/bin/python3
    2. # -*- coding: utf-8 -*-
    3. """
    4. ZetCode PyQt5 tutorial
    5. In this example, we position two push
    6. buttons in the bottom-right corner
    7. of the window.
    8. Author: Jan Bodnar
    9. Website: zetcode.com
    10. Last edited: August 2017
    11. """
    12. import sys
    13. from PyQt5.QtWidgets import (QWidget, QPushButton,
    14. QHBoxLayout, QVBoxLayout, QApplication)
    15. class Example(QWidget):
    16. def __init__(self):
    17. super().__init__()
    18. self.initUI()
    19. def initUI(self):
    20. okButton = QPushButton("OK")
    21. cancelButton = QPushButton("Cancel")
    22. hbox = QHBoxLayout()
    23. hbox.addStretch(1)
    24. hbox.addWidget(okButton)
    25. hbox.addWidget(cancelButton)
    26. vbox = QVBoxLayout()
    27. vbox.addStretch(1)
    28. vbox.addLayout(hbox)
    29. self.setLayout(vbox)
    30. self.setGeometry(300, 300, 300, 150)
    31. self.setWindowTitle('Buttons')
    32. self.show()
    33. if __name__ == '__main__':
    34. app = QApplication(sys.argv)
    35. ex = Example()
    36. sys.exit(app.exec_())

    上面的例子完成了在应用的右下角放了两个按钮的需求。当改变窗口大小的时候,它们能依然保持在相对的位置。我们同时使用了QHBoxLayoutQVBoxLayout

    1. okButton = QPushButton("OK")
    2. cancelButton = QPushButton("Cancel")

    这是创建了两个按钮。

    1. hbox = QHBoxLayout()
    2. hbox.addStretch(1)
    3. hbox.addWidget(okButton)
    4. hbox.addWidget(cancelButton)

    创建一个水平布局,增加两个按钮和弹性空间。stretch函数在两个按钮前面增加了一些弹性空间。下一步我们把这些元素放在应用的右下角。

    1. vbox = QVBoxLayout()
    2. vbox.addStretch(1)
    3. vbox.addLayout(hbox)

    为了布局需要,我们把这个水平布局放到了一个垂直布局盒里面。弹性元素会把所有的元素一起都放置在应用的右下角。

    1. self.setLayout(vbox)

    最后,我们就得到了我们想要的布局。

    程序预览:

    buttons

    栅格布局

    最常用的还是栅格布局了。这种布局是把窗口分为行和列。创建和使用栅格布局,需要使用QGridLayout模块。

    1. #!/usr/bin/python3
    2. # -*- coding: utf-8 -*-
    3. """
    4. ZetCode PyQt5 tutorial
    5. In this example, we create a skeleton
    6. of a calculator using a QGridLayout.
    7. author: Jan Bodnar
    8. website: zetcode.com
    9. last edited: January 2015
    10. """
    11. import sys
    12. from PyQt5.QtWidgets import (QWidget, QGridLayout,
    13. QPushButton, QApplication)
    14. class Example(QWidget):
    15. def __init__(self):
    16. super().__init__()
    17. self.initUI()
    18. def initUI(self):
    19. grid = QGridLayout()
    20. self.setLayout(grid)
    21. names = ['Cls', 'Bck', '', 'Close',
    22. '7', '8', '9', '/',
    23. '4', '5', '6', '*',
    24. '1', '2', '3', '-',
    25. '0', '.', '=', '+']
    26. positions = [(i,j) for i in range(5) for j in range(4)]
    27. for position, name in zip(positions, names):
    28. if name == '':
    29. continue
    30. button = QPushButton(name)
    31. grid.addWidget(button, *position)
    32. self.move(300, 150)
    33. self.setWindowTitle('Calculator')
    34. self.show()
    35. if __name__ == '__main__':
    36. app = QApplication(sys.argv)
    37. ex = Example()
    38. sys.exit(app.exec_())

    这个例子里,我们创建了栅格化的按钮。

    1. grid = QGridLayout()
    2. self.setLayout(grid)

    创建一个QGridLayout实例,并把它放到程序窗口里。

    1. names = ['Cls', 'Bck', '', 'Close',
    2. '7', '8', '9', '/',
    3. '4', '5', '6', '*',
    4. '1', '2', '3', '-',
    5. '0', '.', '=', '+']

    这是我们将要使用的按钮的名称。

    1. positions = [(i,j) for i in range(5) for j in range(4)]

    创建按钮位置列表。

    1. for position, name in zip(positions, names):
    2. if name == '':
    3. continue
    4. button = QPushButton(name)
    5. grid.addWidget(button, *position)

    创建按钮,并使用addWidget()方法把按钮放到布局里面。

    程序预览:

    Calculator skeleton

    制作提交反馈信息的布局

    组件能跨列和跨行展示,这个例子里,我们就试试这个功能。

    1. #!/usr/bin/python3
    2. # -*- coding: utf-8 -*-
    3. """
    4. ZetCode PyQt5 tutorial
    5. In this example, we create a more
    6. complicated window layout using
    7. the QGridLayout manager.
    8. Author: Jan Bodnar
    9. Website: zetcode.com
    10. Last edited: August 2017
    11. """
    12. import sys
    13. from PyQt5.QtWidgets import (QWidget, QLabel, QLineEdit,
    14. QTextEdit, QGridLayout, QApplication)
    15. class Example(QWidget):
    16. def __init__(self):
    17. super().__init__()
    18. self.initUI()
    19. def initUI(self):
    20. title = QLabel('Title')
    21. author = QLabel('Author')
    22. review = QLabel('Review')
    23. titleEdit = QLineEdit()
    24. authorEdit = QLineEdit()
    25. reviewEdit = QTextEdit()
    26. grid = QGridLayout()
    27. grid.setSpacing(10)
    28. grid.addWidget(title, 1, 0)
    29. grid.addWidget(titleEdit, 1, 1)
    30. grid.addWidget(author, 2, 0)
    31. grid.addWidget(authorEdit, 2, 1)
    32. grid.addWidget(review, 3, 0)
    33. grid.addWidget(reviewEdit, 3, 1, 5, 1)
    34. self.setLayout(grid)
    35. self.setGeometry(300, 300, 350, 300)
    36. self.setWindowTitle('Review')
    37. self.show()
    38. if __name__ == '__main__':
    39. app = QApplication(sys.argv)
    40. ex = Example()
    41. sys.exit(app.exec_())

    我们创建了一个有三个标签的窗口。两个行编辑和一个文版编辑,这是用QGridLayout模块搞定的。

    1. grid = QGridLayout()
    2. grid.setSpacing(10)

    创建标签之间的空间。

    1. grid.addWidget(reviewEdit, 3, 1, 5, 1)

    我们可以指定组件的跨行和跨列的大小。这里我们指定这个元素跨5行显示。

    程序预览:

    review example