Python 图形开发:PyQt 三种界面布局解析

QHBoxLayout 水平布局

水平布局,即将各个组件按先后顺序在水平方向上依次排列。

我们以一个 Dialog 窗口和四个简单 Label 作为示例:

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys

class Form(QDialog):
    def __init__(self):
        super(Form, self).__init__()

        layout = QHBoxLayout()
        layout.addWidget(QLabel("A"))
        layout.addWidget(QLabel("B"))
        layout.addWidget(QLabel("C"))
        layout.addWidget(QLabel("D"))

        self.setLayout(layout)

app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()

效果如下:

QVBoxLayout 垂直布局

垂直布局与水平布局只是排列方向不同,用法基本相同。所有组件在垂直方向上依次排列。

同样以四个标签为例:

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys

class Form(QDialog):
    def __init__(self):
        super(Form, self).__init__()

        layout = QHBoxLayout()
        layout.addWidget(QLabel("A"))
        layout.addWidget(QLabel("B"))
        layout.addWidget(QLabel("C"))
        layout.addWidget(QLabel("D"))

        self.setLayout(layout)

app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()

效果如下:

QGridLayout 网格布局

网格布局,以行和列来确定组件的位置。在使用layout.addWidget添加组件的时候,需要在组件后面跟上另外两个坐标参数,第一个表示行,从0开始;第二个表示列,也是从0开始。

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys

class Form(QDialog):
    def __init__(self):
        super(Form, self).__init__()

        layout = QGridLayout()
        layout.addWidget(QLabel("A"), 0, 0)
        layout.addWidget(QLabel("B"), 0, 1)
        layout.addWidget(QLabel("C"), 1, 0)
        layout.addWidget(QLabel("D"), 1, 1)

        self.setLayout(layout)

app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()

效果如下:

网格布局还能够指定组件所占的行数和列数,即组件能够跨行或跨列。如果要让组件占据大于一行一列的空间,可以在网格布局 addWidget 方法的参数中加上所跨行数和所跨列数,以标签C占据一行两列为例:

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys

class Form(QDialog):
    def __init__(self):
        super(Form, self).__init__()

        layout = QGridLayout()
        layout.addWidget(QLabel("A"), 0, 0)
        layout.addWidget(QLabel("B"), 0, 1)
        layout.addWidget(QLabel("C"), 1, 0, 1, 2)
        layout.addWidget(QLabel("D"), 1, 2)

        self.setLayout(layout)

app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()

效果如下:

布局类方法

无论是QHBoxLayout、QVBoxLayout还是QGridLayout,都是属于布局对象,对于布局对象来说,很多操作都基本相同。

1. 添加子布局

在上面的例子中,我们使用布局对象的 addWidget 方法来添加组件,然后调用父对象的 setLayout 方法来采用该布局。

除了能够添加组件,我们还能够在布局中加入子布局,实现复杂的组件排列方式。添加子布局使用 addLayout 方法:

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys

class Form(QDialog):
    def __init__(self):
        super(Form, self).__init__()

        childLayout = QGridLayout()
        childLayout.addWidget(QLabel("A"), 0, 0)
        childLayout.addWidget(QLabel("B"), 0, 1)
        childLayout.addWidget(QLabel("C"), 1, 0)
        childLayout.addWidget(QLabel("D"), 1, 1)

        layout = QVBoxLayout()
        layout.addWidget(QLabel("First Label"))
        layout.addLayout(childLayout)

        self.setLayout(layout)

app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()

我们在外层使用了一个垂直布局,该垂直布局内先是 QLabel,然后是子布局 QGridLayout。这个子布局为网格布局,也就是上面给出的例子。这样,我们就在垂直布局中加入了网格布局,实现了垂直布局与网格布局的混合。

效果如下:

2.填充固定空白

有时候,我们希望两个组件之间留有一定的空间,此时可以通过 addSpacing 方法来添加空白。addSpacing 接收一个数值参数,用来指定空白的大小。

例如:

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys

class Form(QDialog):
    def __init__(self):
        super(Form, self).__init__()

        childLayout = QGridLayout()
        childLayout.addWidget(QLabel("A"), 0, 0)
        childLayout.addWidget(QLabel("B"), 0, 1)
        childLayout.addWidget(QLabel("C"), 0, 1)
        childLayout.addWidget(QLabel("D"), 1, 1)

        layout = QVBoxLayout()
        layout.addWidget(QLabel("First Label"))
        layout.addSpacing(30)
        layout.addLayout(childLayout)

        self.setLayout(layout)

app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()

这个例子是在上一个例子的基础上进行修改的:在第一个组件和第二个组件之间加入了空白,使两个组件之间留有一定的空间。

效果如下:

3. 填充最大空白

在某些情况下,我们不仅希望能够用空白来占据某些空间,还希望这些空白尽可能大,但不至于覆盖余下的组件。这种情况下,我们可以使用 addStretch 方法来实现:

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys

class Form(QDialog):
    def __init__(self):
        super(Form, self).__init__()

        buttonLayout = QHBoxLayout()
        buttonLayout.addStretch()
        buttonLayout.addWidget(QPushButton("Yes"))
        buttonLayout.addWidget(QPushButton("No"))

        layout = QVBoxLayout()
        layout.addWidget(QLabel("Do you want to close this window without saving the data?"))
        layout.addLayout(buttonLayout)

        self.setLayout(layout)

app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()

我们在按钮所在的水平布局里,一开始就加入了空白填充,这样一来,空白会尽可能地占据水平空间左侧,只留下最小的右侧空间给两个按钮。

效果如下:

总结

PyQt 为我们提供了上述三种最常见的布局,以及布局对应的方法。虽然单看这些布局非常简单,但是通过这些布局的组合,以及布局方法的调用,我们可以创建出非常复杂的界面。

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注