组件(widgets)是构建一个应用的基础模块。PyQt5有广泛的各式各样的组件,包含按钮,复选按钮,滑块条,和列表框。在这个部分的教程中,我们将学习几种有用的组件:复选按钮(QCheckBox),切换按钮(ToggleButton),滑块条(QSlider),进度条(ProgressBar)和日历组件(QCalendarWidget)。
复选框组件有两种状态:选中和未选中。它是由一个选择框和一个标签组成的。一个应用中,复选框是典型的用来代表有效或无效状态的组件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
ZetCode PyQt5 tutorial
In this example, a QCheckBox widget
is used to toggle the title of a window.
author: Jan Bodnar
website: zetcode.com
last edited: January 2015
"""
import
sys
from
PyQt5.QtWidgets
import
QWidget, QCheckBox, QApplication
from
PyQt5.QtCore
import
Qt
class
Example(QWidget):
def
__init__(
self
):
super
().__init__()
self
.initUI()
def
initUI(
self
):
cb
=
QCheckBox(
'Show title'
,
self
)
cb.move(
20
,
20
)
cb.toggle()
cb.stateChanged.connect(
self
.changeTitle)
self
.setGeometry(
300
,
300
,
250
,
150
)
self
.setWindowTitle(
'QCheckBox'
)
self
.show()
def
changeTitle(
self
, state):
if
state
=
=
Qt.Checked:
self
.setWindowTitle(
'QCheckBox'
)
else
:
self
.setWindowTitle('')
if
__name__
=
=
'__main__'
:
app
=
QApplication(sys.argv)
ex
=
Example()
sys.exit(app.exec_())
|
在我们的例子中,我们创建了一个复选框,用来切换窗口标题。
1
|
cb
=
QCheckBox(
'Show title'
,
self
)
|
这是QCheckBox类的构造方法。
1
|
cb.toggle()
|
我们需要设置窗口标题,所以我们必须选中复选框。如果不选中复选框,默认情况下复选框不会被选中所以窗口标题也不会被设置。
1
|
cb.stateChanged.connect(
self
.changeTitle)
|
将我们自定义的changeTitle()槽方法和stateChanged信号连接。changeTitle()方法将用于切换窗口标题。
1
2
3
4
5
6
|
def
changeTitle(
self
, state):
if
state
=
=
Qt.Checked:
self
.setWindowTitle(
'QCheckBox'
)
else
:
self
.setWindowTitle('')
|
复选框组件的状态会传入changeTitle()方法的state参数。如果复选框被选中,我们设置窗口标题。否则,我们把窗口标题设置成一个空字符串。
切换按钮是QPushButton的特殊模式。切换按钮有两种状态:按下和没有按下。我们可以通过点击它在两种状态之间切换。下面的列子展示了切换按钮合适出现的情景。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
ZetCode PyQt5 tutorial
In this example, we create three toggle buttons.
They will control the background colour of a
QFrame.
author: Jan Bodnar
website: zetcode.com
last edited: January 2015
"""
import
sys
from
PyQt5.QtWidgets
import
(QWidget, QPushButton,
QFrame, QApplication)
from
PyQt5.QtGui
import
QColor
class
Example(QWidget):
def
__init__(
self
):
super
().__init__()
self
.initUI()
def
initUI(
self
):
self
.col
=
QColor(
0
,
0
,
0
)
redb
=
QPushButton(
'Red'
,
self
)
redb.setCheckable(
True
)
redb.move(
10
,
10
)
redb.clicked[
bool
].connect(
self
.setColor)
redb
=
QPushButton(
'Green'
,
self
)
redb.setCheckable(
True
)
redb.move(
10
,
60
)
redb.clicked[
bool
].connect(
self
.setColor)
blueb
=
QPushButton(
'Blue'
,
self
)
blueb.setCheckable(
True
)
blueb.move(
10
,
110
)
blueb.clicked[
bool
].connect(
self
.setColor)
self
.square
=
QFrame(
self
)
self
.square.setGeometry(
150
,
20
,
100
,
100
)
self
.square.setStyleSheet(
"QWidget { background-color: %s }"
%
self
.col.name())
self
.setGeometry(
300
,
300
,
280
,
170
)
self
.setWindowTitle(
'Toggle button'
)
self
.show()
def
setColor(
self
, pressed):
source
=
self
.sender()
if
pressed:
val
=
255
else
: val
=
0
if
source.text()
=
=
"Red"
:
self
.col.setRed(val)
elif
source.text()
=
=
"Green"
:
self
.col.setGreen(val)
else
:
self
.col.setBlue(val)
self
.square.setStyleSheet(
"QFrame { background-color: %s }"
%
self
.col.name())
if
__name__
=
=
'__main__'
:
app
=
QApplication(sys.argv)
ex
=
Example()
sys.exit(app.exec_())
|
在我们的例子中,我们创建了三个切换按钮和一个QWidget组件。我们把QWidget组件的背景颜色设置为黑色。切换按钮将在红色,绿色和蓝色的RGB值部分进行切换。QWidget组件的背景颜色将取决于哪一个切换按钮被按下。
1
|
self
.col
=
QColor(
0
,
0
,
0
)
|
这里是初始化,让RGB值为黑色。
1
2
3
|
redb
=
QPushButton(
'Red'
,
self
)
redb.setCheckable(
True
)
redb.move(
10
,
10
)
|
要创建切换按钮,就要创建QPushButton,并且调用setCheckable()方法让它可被选中。
1
|
redb.clicked[
bool
].connect(
self
.setColor)
|
我们把clicked信号连接到我们定义的方法上。我们使用clicked信号来操作布尔值。
1
|
source
=
self
.sender()
|
我们获得发生状态切换的按钮。
1
2
|
if
source.text()
=
=
"Red"
:
self
.col.setRed(val)
|
在这种情况下,如果发生切换的是red按钮,我们更新RGB值中的红色部分的颜色值。
1
|
self
.square.setStyleSheet(
"QWidget { background-color: %s }"
%
self
.col.name())
|
我们使用样式表来改变背景颜色。
Figure: Toggle button
滑块条(QSlider)组件有一个简单的可调节手柄。这个手柄可以前后拖动。我们可以使用这个方式来选择具体的数值。有时使用滑块条比直接输入数字或使用数值选择框更自然,在我们下面的例子中,我们将显示一个滑块条和一个标签。标签将会显示一个图像。滑块条将控制标签。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
ZetCode PyQt5 tutorial
This example shows a QSlider widget.
author: Jan Bodnar
website: zetcode.com
last edited: January 2015
"""
import
sys
from
PyQt5.QtWidgets
import
(QWidget, QSlider,
QLabel, QApplication)
from
PyQt5.QtCore
import
Qt
from
PyQt5.QtGui
import
QPixmap
class
Example(QWidget):
def
__init__(
self
):
super
().__init__()
self
.initUI()
def
initUI(
self
):
sld
=
QSlider(Qt.Horizontal,
self
)
sld.setFocusPolicy(Qt.NoFocus)
sld.setGeometry(
30
,
40
,
100
,
30
)
sld.valueChanged[
int
].connect(
self
.changeValue)
self
.label
=
QLabel(
self
)
self
.label.setPixmap(QPixmap(
'mute.png'
))
self
.label.setGeometry(
160
,
40
,
80
,
30
)
self
.setGeometry(
300
,
300
,
280
,
170
)
self
.setWindowTitle(
'QSlider'
)
self
.show()
def
changeValue(
self
, value):
if
value
=
=
0
:
self
.label.setPixmap(QPixmap(
'mute.png'
))
elif
value >
0
and
value <
=
30
:
self
.label.setPixmap(QPixmap(
'min.png'
))
elif
value >
30
and
value <
80
:
self
.label.setPixmap(QPixmap(
'med.png'
))
else
:
self
.label.setPixmap(QPixmap(
'max.png'
))
if
__name__
=
=
'__main__'
:
app
=
QApplication(sys.argv)
ex
=
Example()
sys.exit(app.exec_())
|
在我们的例子中,我们模拟了一个音量控制器。通过拖动滑块条的把手,我们可以改变标签的图像。
1
|
sld
=
QSlider(Qt.Horizontal,
self
)
|
这里我们创建了一个横向的滑块条。
1
2
|
self
.label
=
QLabel(
self
)
self
.label.setPixmap(QPixmap(
'mute.png'
))
|
我们创建了一个标签组件,并且设置一个初始的无声图片。
1
|
sld.valueChanged[
int
].connect(
self
.changeValue)
|
我们把valueChanged
信号连接到我们自定义的 changeValue()方法上。
1
2
3
|
if
value
=
=
0
:
self
.label.setPixmap(QPixmap(
'mute.png'
))
...
|
这里实现了根据滑块条的值,我们设置不同的标签图片。在上面的代码中,如果滑块条的值等于零,我们为标签设置mute.png图片。
Figure: QSlider widget
当我们处理耗时长的任务时,我们需要用到进度条组件。它通过动画的方式让我们了解任务正在处理中。在PyQt5中,进度条组件提供了横向和纵向的进度条选择。程序员可以设置进度条的最大值和最小值。进度条的默认值是0~99。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
ZetCode PyQt5 tutorial
This example shows a QProgressBar widget.
author: Jan Bodnar
website: zetcode.com
last edited: January 2015
"""
import
sys
from
PyQt5.QtWidgets
import
(QWidget, QProgressBar,
QPushButton, QApplication)
from
PyQt5.QtCore
import
QBasicTimer
class
Example(QWidget):
def
__init__(
self
):
super
().__init__()
self
.initUI()
def
initUI(
self
):
self
.pbar
=
QProgressBar(
self
)
self
.pbar.setGeometry(
30
,
40
,
200
,
25
)
self
.btn
=
QPushButton(
'Start'
,
self
)
self
.btn.move(
40
,
80
)
self
.btn.clicked.connect(
self
.doAction)
self
.timer
=
QBasicTimer()
self
.step
=
0
self
.setGeometry(
300
,
300
,
280
,
170
)
self
.setWindowTitle(
'QProgressBar'
)
self
.show()
def
timerEvent(
self
, e):
if
self
.step >
=
100
:
self
.timer.stop()
self
.btn.setText(
'Finished'
)
return
self
.step
=
self
.step
+
1
self
.pbar.setValue(
self
.step)
def
doAction(
self
):
if
self
.timer.isActive():
self
.timer.stop()
self
.btn.setText(
'Start'
)
else
:
self
.timer.start(
100
,
self
)
self
.btn.setText(
'Stop'
)
if
__name__
=
=
'__main__'
:
app
=
QApplication(sys.argv)
ex
=
Example()
sys.exit(app.exec_())
|
在我们的例子中有一个横向进度条和一个按钮。按钮控制滑块条的开始和停止。
1
|
self
.pbar
=
QProgressBar(
self
)
|
这是滑块条类的构造方法。
1
|
self
.timer
=
QtCore.QBasicTimer()
|
我们用定时器对象来激活进度条。
1
|
self
.timer.start(
100
,
self
)
|
为了开启定时器事件,我们调用了start()方法。这个方法有两个参数:定时时间和接收定时器事件的对象。
1
2
3
4
5
6
7
8
9
10
|
def
timerEvent(
self
, e):
if
self
.step >
=
100
:
self
.timer.stop()
self
.btn.setText(
'Finished'
)
return
self
.step
=
self
.step
+
1
self
.pbar.setValue(
self
.step)
|
每个QObject类和它的子类都有timerEvent()事件处理函数用于处理定时事件。为了对定时器事件作出反馈,我们重新实现了这个事件处理函数。
1
2
3
4
5
6
7
8
9
|
def
doAction(
self
):
if
self
.timer.isActive():
self
.timer.stop()
self
.btn.setText(
'Start'
)
else
:
self
.timer.start(
100
,
self
)
self
.btn.setText(
'Stop'
)
|
在doAction()方法中,我们开始和停止定时器。
Figure: QProgressBar
QCalendarWidget类提供了一个基于月的日历组件。它允许用户通过简单的直观的方式选择日期。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
ZetCode PyQt5 tutorial
This example shows a QCalendarWidget widget.
author: Jan Bodnar
website: zetcode.com
last edited: January 2015
"""
import
sys
from
PyQt5.QtWidgets
import
(QWidget, QCalendarWidget,
QLabel, QApplication)
from
PyQt5.QtCore
import
QDate
class
Example(QWidget):
def
__init__(
self
):
super
().__init__()
self
.initUI()
def
initUI(
self
):
cal
=
QCalendarWidget(
self
)
cal.setGridVisible(
True
)
cal.move(
20
,
20
)
cal.clicked[QDate].connect(
self
.showDate)
self
.lbl
=
QLabel(
self
)
date
=
cal.selectedDate()
self
.lbl.setText(date.toString())
self
.lbl.move(
130
,
260
)
self
.setGeometry(
300
,
300
,
350
,
300
)
self
.setWindowTitle(
'Calendar'
)
self
.show()
def
showDate(
self
, date):
self
.lbl.setText(date.toString())
if
__name__
=
=
'__main__'
:
app
=
QApplication(sys.argv)
ex
=
Example()
sys.exit(app.exec_())
|
以上的例子展示一个日历组件和标签组件。功能是日历中选择的日期会显示在标签组件中。
1
|
cal
=
QCalendarWidget(
self
)
|
创建QCalendarWidget类。
1
|
cal.clicked[QDate].connect(
self
.showDate)
|
如果我们在组件上选择了一个日期,clicked[QDate]
信号会被发射。我们把这个信号和自定义的showDate()方法连接。
1
2
3
|
def
showDate(
self
, date):
self
.lbl.setText(date.toString())
|
我们通过selectedDate()方法检索被选中的日期。然后我们把选中的日期对象转化成字符串显示在标签组件上。