
本文介绍的 3 个控件处理的是连续量,用拖拽的方式在一段区间里取一个值,或者把一件事情的完成程度可视化表示出来,包括:
QSlider:滑块QProgressBar:进度条QDial:仪表盘
程序界面中的音量、亮度、缩放、导出进度等,都是用这 3 个控件实现。
QSlider
QSlider 是最常用的连续取值控件,横向用于音量、缩放,纵向用于刻度尺式输入。
构造函数中传入 orientation 参数,指定滑块的方向(Qt.Orientation.Horizontal 或 Qt.Orientation.Vertical)。
QSlider 的常用方法包括:
setMinimum:设置最小值setMaximum:设置最大值setRange:一次性设置最小、最大值setValue:设置滑块当前值value:获取当前值singleStep:设置方向键单步增量pageStep:设置 PageUp/PageDown 大步长setTickPosition:设置刻度位置setTickInterval:设置刻度间隔invertedAppearance:是否反向显示(水平条从右到左)invertedControls:是否反转键盘控制方向
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
| import sys
from PySide6.QtWidgets import (
QApplication, QWidget, QVBoxLayout, QHBoxLayout,
QSlider, QLabel, QPushButton, QSpinBox
)
from PySide6.QtCore import Qt
class SliderDemo(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QSlider 常用方法演示")
self.resize(600, 400)
layout = QVBoxLayout()
# 滑块本体
self.slider = QSlider(Qt.Horizontal)
# setRange(min, max) 一次性设置范围
self.slider.setRange(0, 100)
# setValue 设置初始值
self.slider.setValue(50)
# setSingleStep 方向键单步
self.slider.setSingleStep(2)
# setPageStep PageUp/PageDown步长
self.slider.setPageStep(10)
# 刻度
self.slider.setTickPosition(QSlider.TicksBelow)
self.slider.setTickInterval(10)
# 显示当前value
self.label_val = QLabel(f"当前值:{self.slider.value()}")
layout.addWidget(self.label_val)
layout.addWidget(self.slider)
# 按钮组
h_layout = QHBoxLayout()
btn_min = QPushButton("setMinimum(10)")
btn_min.clicked.connect(lambda: self.slider.setMinimum(10))
btn_max = QPushButton("setMaximum(90)")
btn_max.clicked.connect(lambda: self.slider.setMaximum(90))
btn_reset_range = QPushButton("setRange(0,100)")
btn_reset_range.clicked.connect(lambda: self.slider.setRange(0, 100))
btn_set_val = QPushButton("setValue(50)")
btn_set_val.clicked.connect(lambda: self.slider.setValue(50))
h_layout.addWidget(btn_min)
h_layout.addWidget(btn_max)
h_layout.addWidget(btn_reset_range)
h_layout.addWidget(btn_set_val)
layout.addLayout(h_layout)
h_layout2 = QHBoxLayout()
btn_tick_none = QPushButton("无刻度")
btn_tick_none.clicked.connect(lambda: self.slider.setTickPosition(QSlider.NoTicks))
btn_tick_below = QPushButton("刻度在下")
btn_tick_below.clicked.connect(lambda: self.slider.setTickPosition(QSlider.TicksBelow))
btn_tick_above = QPushButton("刻度在上")
btn_tick_above.clicked.connect(lambda: self.slider.setTickPosition(QSlider.TicksAbove))
h_layout2.addWidget(btn_tick_none)
h_layout2.addWidget(btn_tick_below)
h_layout2.addWidget(btn_tick_above)
layout.addLayout(h_layout2)
h_layout3 = QHBoxLayout()
btn_inv_app = QPushButton("切换 invertedAppearance")
btn_inv_app.clicked.connect(self.toggle_inv_appearance)
btn_inv_ctrl = QPushButton("切换 invertedControls")
btn_inv_ctrl.clicked.connect(self.toggle_inv_controls)
h_layout3.addWidget(btn_inv_app)
h_layout3.addWidget(btn_inv_ctrl)
layout.addLayout(h_layout3)
# 单步、大步修改
h_layout4 = QHBoxLayout()
sp_single = QSpinBox()
sp_single.setRange(1, 20)
sp_single.setValue(2)
sp_single.valueChanged.connect(self.slider.setSingleStep)
h_layout4.addWidget(QLabel("singleStep:"))
h_layout4.addWidget(sp_single)
sp_page = QSpinBox()
sp_page.setRange(1, 30)
sp_page.setValue(10)
sp_page.valueChanged.connect(self.slider.setPageStep)
h_layout4.addWidget(QLabel("pageStep:"))
h_layout4.addWidget(sp_page)
layout.addLayout(h_layout4)
self.setLayout(layout)
# 值变化信号
self.slider.valueChanged.connect(self.on_value_changed)
def on_value_changed(self, v):
self.label_val.setText(f"当前值:{v}")
def toggle_inv_appearance(self):
flag = not self.slider.invertedAppearance()
self.slider.setInvertedAppearance(flag)
def toggle_inv_controls(self):
flag = not self.slider.invertedControls()
self.slider.setInvertedControls(flag)
app = QApplication(sys.argv)
window = SliderDemo()
window.show()
sys.exit(app.exec())
|
演示效果如下:

QProgressBar
QProgressBar 只负责显示进度,不接收用户输入。
QProgressBar 的常用方法包括:
setMinimum:设置最小值setMaximum:设置最大值setRange:一次性设置最小、最大值setValue:设置当前进度值value:获取当前进度值setFormat:自定义文字模板%p = 百分比,%v = 当前值,%m = 最大值
resetFormat:恢复默认格式(%p%)setTextVisible:是否显示进度文字setAlignment:文字对齐方式setInvertedAppearance:反向填充(从右往左涨)setOrientation:水平 / 垂直方向reset:重置到最小值text:获取当前显示文本
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
| import sys
from PySide6.QtWidgets import (
QApplication, QWidget, QVBoxLayout, QHBoxLayout,
QProgressBar, QLabel, QPushButton, QSpinBox
)
from PySide6.QtCore import Qt
class ProgressBarDemo(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QProgressBar 常用方法演示")
self.resize(650, 450)
layout = QVBoxLayout()
# 进度条本体
self.bar = QProgressBar()
self.bar.setRange(0, 100)
self.bar.setValue(30)
self.bar.setAlignment(Qt.AlignCenter)
layout.addWidget(QLabel("进度条:"))
layout.addWidget(self.bar)
# 状态文本
self.label_info = QLabel(f"value={self.bar.value()}, text={self.bar.text()}")
layout.addWidget(self.label_info)
# 范围、setValue
h1 = QHBoxLayout()
btn_set_min = QPushButton("setMinimum(10)")
btn_set_min.clicked.connect(lambda: self.bar.setMinimum(10))
btn_set_max = QPushButton("setMaximum(90)")
btn_set_max.clicked.connect(lambda: self.bar.setMaximum(90))
btn_reset_range = QPushButton("setRange(0,100)")
btn_reset_range.clicked.connect(lambda: self.bar.setRange(0, 100))
btn_set_val = QPushButton("setValue(60)")
btn_set_val.clicked.connect(lambda: self.bar.setValue(60))
h1.addWidget(btn_set_min)
h1.addWidget(btn_set_max)
h1.addWidget(btn_reset_range)
h1.addWidget(btn_set_val)
layout.addLayout(h1)
# 不确定模式、reset
h2 = QHBoxLayout()
btn_unknown = QPushButton("不确定模式 setRange(0,0)")
btn_unknown.clicked.connect(lambda: self.bar.setRange(0, 0))
btn_reset = QPushButton("reset()")
btn_reset.clicked.connect(self.bar.reset)
h2.addWidget(btn_unknown)
h2.addWidget(btn_reset)
layout.addLayout(h2)
# 文字控制:显示隐藏、格式
h3 = QHBoxLayout()
btn_text_hide = QPushButton("隐藏文字 setTextVisible(False)")
btn_text_hide.clicked.connect(lambda: self.bar.setTextVisible(False))
btn_text_show = QPushButton("显示文字 setTextVisible(True)")
btn_text_show.clicked.connect(lambda: self.bar.setTextVisible(True))
btn_fmt1 = QPushButton('格式 "%v/%m"')
btn_fmt1.clicked.connect(lambda: self.bar.setFormat("%v/%m"))
btn_fmt2 = QPushButton('格式 "%p% 已完成"')
btn_fmt2.clicked.connect(lambda: self.bar.setFormat("%p% 已完成"))
btn_fmt_reset = QPushButton("resetFormat()")
btn_fmt_reset.clicked.connect(self.bar.resetFormat)
h3.addWidget(btn_text_hide)
h3.addWidget(btn_text_show)
h3.addWidget(btn_fmt1)
h3.addWidget(btn_fmt2)
h3.addWidget(btn_fmt_reset)
layout.addLayout(h3)
# 反向、方向
h4 = QHBoxLayout()
btn_inv = QPushButton("切换 invertedAppearance")
btn_inv.clicked.connect(self.toggle_inv)
btn_hori = QPushButton("水平")
btn_hori.clicked.connect(lambda: self.bar.setOrientation(Qt.Horizontal))
btn_vert = QPushButton("垂直")
btn_vert.clicked.connect(lambda: self.bar.setOrientation(Qt.Vertical))
h4.addWidget(btn_inv)
h4.addWidget(btn_hori)
h4.addWidget(btn_vert)
layout.addLayout(h4)
# 手动输入值
h5 = QHBoxLayout()
sp_val = QSpinBox()
sp_val.setRange(0, 200)
sp_val.setValue(30)
sp_val.valueChanged.connect(self.bar.setValue)
h5.addWidget(QLabel("修改value:"))
h5.addWidget(sp_val)
layout.addLayout(h5)
self.setLayout(layout)
self.bar.valueChanged.connect(self.on_change)
def on_change(self, v):
self.label_info.setText(f"value={v}, text={self.bar.text()}")
def toggle_inv(self):
flag = not self.bar.invertedAppearance()
self.bar.setInvertedAppearance(flag)
app = QApplication(sys.argv)
window = ProgressBarDemo()
window.show()
sys.exit(app.exec())
|
演示效果如下:

QDial
QDial 用于选择角度,内置角度选择器,支持自定义角度显示格式、角度范围,底层依赖 QAngle 对象。
QDial 的常用方法包括:
setMinimum:设置最小值setMaximum:设置最大值setRange:一次性设置最小、最大值setValue:设置当前值value:获取当前值setSingleStep:单步增量(键盘 / 方向键)setPageStep:PageUp/PageDown 大步长setWrapping:是否循环环绕(转到尽头可以继续转,0 和最大值相连)setNotchesVisible:是否显示刻度凹槽setNotchTarget:刻度目标间距(控制刻度疏密)invertedAppearance:反向,默认顺时针增大;开启后逆时针增大
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
| import sys
from PySide6.QtWidgets import (
QApplication, QWidget, QVBoxLayout, QHBoxLayout,
QDial, QLabel, QPushButton, QSpinBox
)
from PySide6.QtCore import Qt
class QDialDemo(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QDial 常用方法演示")
self.resize(600, 450)
layout = QVBoxLayout()
# 旋钮本体
self.dial = QDial()
self.dial.setRange(0, 100)
self.dial.setValue(50)
self.dial.setSingleStep(1)
self.dial.setPageStep(10)
self.dial.setNotchesVisible(True)
self.dial.setNotchTarget(3.0)
layout.addWidget(QLabel("QDial 旋钮:"))
layout.addWidget(self.dial, alignment=Qt.AlignmentFlag.AlignCenter)
self.label_val = QLabel(f"当前值:{self.dial.value()}")
layout.addWidget(self.label_val)
# 范围、setValue
h1 = QHBoxLayout()
btn_min = QPushButton("setMinimum(10)")
btn_min.clicked.connect(lambda: self.dial.setMinimum(10))
btn_max = QPushButton("setMaximum(90)")
btn_max.clicked.connect(lambda: self.dial.setMaximum(90))
btn_range = QPushButton("setRange(0,100)")
btn_range.clicked.connect(lambda: self.dial.setRange(0, 100))
btn_setval = QPushButton("setValue(50)")
btn_setval.clicked.connect(lambda: self.dial.setValue(50))
h1.addWidget(btn_min)
h1.addWidget(btn_max)
h1.addWidget(btn_range)
h1.addWidget(btn_setval)
layout.addLayout(h1)
# 环绕 wrapping
h2 = QHBoxLayout()
btn_wrap_on = QPushButton("开启环绕 setWrapping(True)")
btn_wrap_on.clicked.connect(lambda: self.dial.setWrapping(True))
btn_wrap_off = QPushButton("关闭环绕 setWrapping(False)")
btn_wrap_off.clicked.connect(lambda: self.dial.setWrapping(False))
h2.addWidget(btn_wrap_on)
h2.addWidget(btn_wrap_off)
layout.addLayout(h2)
# 刻度显示、刻度间距
h3 = QHBoxLayout()
btn_notch_show = QPushButton("显示刻度 setNotchesVisible(True)")
btn_notch_show.clicked.connect(lambda: self.dial.setNotchesVisible(True))
btn_notch_hide = QPushButton("隐藏刻度 setNotchesVisible(False)")
btn_notch_hide.clicked.connect(lambda: self.dial.setNotchesVisible(False))
h3.addWidget(btn_notch_show)
h3.addWidget(btn_notch_hide)
layout.addLayout(h3)
# 反向
h4 = QHBoxLayout()
btn_inv = QPushButton("切换 invertedAppearance")
btn_inv.clicked.connect(self.toggle_inv)
h4.addWidget(btn_inv)
layout.addLayout(h4)
# 单步、大步、手动赋值
h5 = QHBoxLayout()
sp_single = QSpinBox()
sp_single.setRange(1, 20)
sp_single.setValue(1)
sp_single.valueChanged.connect(self.dial.setSingleStep)
h5.addWidget(QLabel("singleStep:"))
h5.addWidget(sp_single)
sp_page = QSpinBox()
sp_page.setRange(1, 30)
sp_page.setValue(10)
sp_page.valueChanged.connect(self.dial.setPageStep)
h5.addWidget(QLabel("pageStep:"))
h5.addWidget(sp_page)
sp_target = QSpinBox()
sp_target.setRange(1, 10)
sp_target.setValue(3)
sp_target.valueChanged.connect(lambda v: self.dial.setNotchTarget(float(v)))
h5.addWidget(QLabel("notchTarget:"))
h5.addWidget(sp_target)
layout.addLayout(h5)
self.setLayout(layout)
self.dial.valueChanged.connect(self.on_changed)
def on_changed(self, v):
self.label_val.setText(f"当前值:{v}")
def toggle_inv(self):
flag = not self.dial.invertedAppearance()
self.dial.setInvertedAppearance(flag)
app = QApplication(sys.argv)
window = QDialDemo()
window.show()
sys.exit(app.exec())
|
演示效果如下:

小结
QSlider、QProgressBar、QDial 都属于数值可视化控件,但定位和交互场景差别明显:
- QSlider(滑动条):线性拖拽交互,适合在一段区间内精细调节参数,支持水平 / 垂直、刻度显示,是最通用的调节控件;
- QProgressBar(进度条):侧重状态展示,多用于任务进度加载,支持百分比自定义文本、不确定加载动画,一般只用来展示,不用于用户调节;
- QDial(旋钮):环形旋转交互,自带环绕模式,适合音量、角度等环形参数调节,交互氛围感更强。