进度条类控件主要显示任务的执行进度,PyQt5中提供了进度条控件和滑块控件这两种类型的进度条类控件。其中,进度条控件是通常所看到的进度条,用ProgressBar控件表示;而滑块控件是以刻度线的形式出现。本节将对PyQt5中的进度条类控件进行详细讲解。

1  ProgressBar:进度条


ProgressBar控件表示进度条,通常在执行长时间任务时,用进度条告诉用户当前的进展情况。

ProgressBar控件对应PyQt5中的QProgressBar类,它其实就是QProgressBar类的一个对象。QProgressBar类的常用方法及说明如表所示。

方    法说    明
setMinimum()设置进度条的最小值,默认值为0
setMaximum()设置进度条的最大值,默认值为99
setRange()设置进度条的取值范围,相当于setMinimum()和setMaximum()方法的结合
setValue()设置进度条的当前值
setFormat()设置进度条的文字显示格式,有以下3种格式:

◆ %p%:显示完成的百分比,默认格式

◆ %v:显示当前的进度值

◆ %m:显示总的步长值
setAlignment()设置对齐方式,有水平和垂直两种,分别如下:

◆ 水平对齐方式:

■  Qt.AlignLeft:左对齐

■  Qt.AlignHCenter:水平居中对齐

■  Qt.AlignRight:右对齐

■  Qt.AlignJustify:两端对齐

◆ 垂直对齐方式:

■  Qt.AlignTop:顶部对齐

■  Qt.AlignVCenter:垂直居中

■  Qt.AlignBottom:底部对齐
setLayoutDirection()设置进度条的布局方向,支持以下3个方向值:

◆ Qt.LeftToRight:从左至右

◆ Qt.RightToLeft:从右至左

◆ Qt.LayoutDirectionAuto:跟随布局方向自动调整
setOrientation()设置进度条的显示方向,有以下两个方向:

◆ Qt.Horizontal:水平方向

◆ Qt.Vertical:垂直方向
setInvertedAppearance()设置进度条是否以反方向显示进度
setTextDirection()设置进度条的文本显示方向,有以下两个方向:

◆ QProgressBar.TopToBottom:从上到下

◆ QProgressBar.BottomToTop:从下到上
setProperty()对进度条的属性进行设置,可以是任何属性,比如,self.progressBar.setProperty("value", 24)
minimum()获取进度条的最小值
maximum()获取进度条的最大值
value()获取进度条的当前值

ProgressBar控件中最常用的信号是valueChanged,在进度条的值发生改变时发射。

通过对ProgressBar控件的显示方向、对齐方式、布局方向等进行设置,该控件可以支持4种水平进度条显示方式和两种垂直进度条显示方式,它们的效果如图所示,用户可以根据自身需要选择适合自己的显示方式。

Pasted image 20250901205656

Tip: 多学两招 如果最小值和最大值都设置为0,那么进度条会显示为一个不断循环滚动的繁忙进度,而不是步骤中显示的百分比。

实例 模拟一个跑马灯效果

打开Qt Designer设计器,创建一个窗口,并向窗口中添加4个ProgressBar控件和一个PushButton控件,然后将该窗口转换为.py文件,在.py文件中对进度条和PushButton按钮的clicked信号进行绑定,代码如下:

from PyQt5 import QtCore, QtGui, QtWidgets  
  
class Ui_MainWindow(object):  
    def setupUi(self, MainWindow):  
        MainWindow.setObjectName("MainWindow")  
        MainWindow.resize(305, 259)  
        self.centralwidget = QtWidgets.QWidget(MainWindow)  
        self.centralwidget.setObjectName("centralwidget")  
        self.progressBar = QtWidgets.QProgressBar(self.centralwidget)  
        self.progressBar.setGeometry(QtCore.QRect(50, 10, 201, 31))  
        self.progressBar.setLayoutDirection(QtCore.Qt.LeftToRight)  
        self.progressBar.setProperty("value", -1)  
        self.progressBar.setAlignment(QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop)  
        self.progressBar.setTextVisible(True)  
        self.progressBar.setOrientation(QtCore.Qt.Horizontal)  
        self.progressBar.setTextDirection(QtWidgets.QProgressBar.TopToBottom)  
        self.progressBar.setFormat("")  
        self.progressBar.setObjectName("progressBar")  
        self.progressBar_2 = QtWidgets.QProgressBar(self.centralwidget)  
        self.progressBar_2.setGeometry(QtCore.QRect(50, 180, 201, 31))  
        self.progressBar_2.setLayoutDirection(QtCore.Qt.RightToLeft)  
        self.progressBar_2.setProperty("value", -1)  
        self.progressBar_2.setAlignment(QtCore.Qt.AlignBottom|QtCore.Qt.AlignHCenter)  
        self.progressBar_2.setTextVisible(True)  
        self.progressBar_2.setOrientation(QtCore.Qt.Horizontal)  
        self.progressBar_2.setTextDirection(QtWidgets.QProgressBar.TopToBottom)  
        self.progressBar_2.setObjectName("progressBar_2")  
        self.progressBar_3 = QtWidgets.QProgressBar(self.centralwidget)  
        self.progressBar_3.setGeometry(QtCore.QRect(20, 10, 31, 201))  
        self.progressBar_3.setLayoutDirection(QtCore.Qt.LeftToRight)  
        self.progressBar_3.setProperty("value", -1)  
        self.progressBar_3.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)  
        self.progressBar_3.setTextVisible(True)  
        self.progressBar_3.setOrientation(QtCore.Qt.Vertical)  
        self.progressBar_3.setTextDirection(QtWidgets.QProgressBar.TopToBottom)  
        self.progressBar_3.setObjectName("progressBar_3")  
        self.progressBar_1 = QtWidgets.QProgressBar(self.centralwidget)  
        self.progressBar_1.setGeometry(QtCore.QRect(250, 10, 31, 201))  
        self.progressBar_1.setLayoutDirection(QtCore.Qt.LeftToRight)  
        self.progressBar_1.setProperty("value", -1)  
        self.progressBar_1.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)  
        self.progressBar_1.setTextVisible(True)  
        self.progressBar_1.setOrientation(QtCore.Qt.Vertical)  
        self.progressBar_1.setTextDirection(QtWidgets.QProgressBar.TopToBottom)  
        self.progressBar_1.setObjectName("progressBar_1")  
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)  
        self.pushButton.setGeometry(QtCore.QRect(90, 220, 101, 31))  
        self.pushButton.setObjectName("pushButton")  
        MainWindow.setCentralWidget(self.centralwidget)  
        self.retranslateUi(MainWindow)  
        QtCore.QMetaObject.connectSlotsByName(MainWindow)  
        self.timer = QtCore.QBasicTimer()             # 创建计时器对象  
        # 为按钮绑定单击信号  
        self.pushButton.clicked.connect(self.running)  
  
    # 控制进度条的滚动效果  
    def running(self):  
        if self.timer.isActive():                 # 判断计时器是否开启  
            self.timer.stop()                     # 停止计时器  
            self.pushButton.setText('开始')            # 设置按钮的文本  
            # 设置4个进度条的最大值为100  
            self.progressBar.setMaximum(100)  
            self.progressBar_1.setMaximum(100)  
            self.progressBar_2.setMaximum(100)  
            self.progressBar_3.setMaximum(100)  
        else:  
            self.timer.start(100,MainWindow)             # 启动计时器  
            self.pushButton.setText('停止')             # 设置按钮的文本  
            # 将4个进度条的最大值和最小值都设置为0,以便显示循环滚动的效果  
            self.progressBar.setMinimum(0)  
            self.progressBar.setMaximum(0)  
            self.progressBar_1.setInvertedAppearance(True)     # 设置进度反方向显示  
            self.progressBar_1.setMinimum(0)  
            self.progressBar_1.setMaximum(0)  
            self.progressBar_2.setMinimum(0)  
            self.progressBar_2.setMaximum(0)  
            self.progressBar_3.setMinimum(0)  
            self.progressBar_3.setMaximum(0)  
  
    def retranslateUi(self, MainWindow):  
        _translate = QtCore.QCoreApplication.translate  
        MainWindow.setWindowTitle(_translate("MainWindow", "跑马灯效果"))  
        self.pushButton.setText(_translate("MainWindow", "开始"))  
  
import sys  
# 程序入口,程序从此处启动PyQt设计的窗体  
if __name__ == '__main__':  
   app = QtWidgets.QApplication(sys.argv)  
   MainWindow = QtWidgets.QMainWindow() # 创建窗体对象  
   ui = Ui_MainWindow()           # 创建PyQt设计的窗体对象  
   ui.setupUi(MainWindow)           # 调用PyQt窗体的方法对窗体对象进行初始化设置  
   MainWindow.show()               # 显示窗体  
   sys.exit(app.exec_())           # 程序关闭时退出进程

Tip: 多学两招 上面代码中用到了QBasicTimer类,该类是QtCore模块中包含的一个类,主要用来为对象提供定时器事件。QBasicTimer定时器是一个重复的定时器,除非调用stop()方法,否则它将发送后续的定时器事件。启动定时器使用start()方法,该方法有两个参数,分别为超时时间(毫秒)和接收事件的对象;而停止定时器时使用stop()方法即可。

运行程序,初始效果如图所示;

Pasted image 20250901210316

单击开始按钮,启动跑马灯效果,并且按钮的文本变为停止,如图所示,单击停止按钮,即可恢复如上图所示的默认效果。

Pasted image 20250901210423

2  自定义等待提示框


在使用PyQt5创建桌面窗口应用程序时,有时会遇到等待长任务执行的情况,PyQt5中提供的ProgressBar控件(即QProgressBar对象)虽然也可以通过循环滚动的方式等待任务执行完成,但与通常见到的类似图所示的等待提示框相比,在美观程度上有所欠缺,因此本节将介绍如何在PyQt5中自定义等待提示。

Pasted image 20250901210612

实例 设置自定义等待提示框

使用PyQt5实现等待提示框时,可以通过加载GIF图片的方式模拟等待提示框,首先在创建主窗口时,在窗口的中间位置添加一个可以加载GIF图片的Label控件,然后再添加两个PushButton按钮,分别用于控制等待提示框的启动停止。代码如下:

from PyQt5 import QtCore, QtGui, QtWidgets  
  
  
class Ui_MainWindow(object):  
  
    def setupUi(self, MainWindow):  
        MainWindow.setObjectName("MainWindow")  
        MainWindow.resize(682, 583)  
        self.centralwidget = QtWidgets.QWidget(MainWindow)  
        self.centralwidget.setObjectName("centralwidget")  
        # 创建主布局  
        self.main_layout = QtWidgets.QVBoxLayout(self.centralwidget)  
        self.loading = QtWidgets.QLabel(self.centralwidget)  
        self.loading.setStyleSheet("")  
        self.loading.setText("")  
        self.loading.setObjectName("loading")  
        # 设置GIF居中显示  
        self.loading.setAlignment(QtCore.Qt.AlignCenter)  
        # 添加到布局  
        self.main_layout.addWidget(self.loading)  
        # 创建按钮布局  
        self.button_layout = QtWidgets.QHBoxLayout()  
        self.pushButton_start = QtWidgets.QPushButton(self.centralwidget)  
        self.pushButton_start.setMinimumSize(QtCore.QSize(100, 50))  
        self.pushButton_start.setObjectName("pushButton_start")  
        self.button_layout.addWidget(self.pushButton_start)  
        # 添加伸缩项,让两个按钮分开  
        self.button_layout.addStretch()  
        self.pushButton_stop = QtWidgets.QPushButton(self.centralwidget)  
        self.pushButton_stop.setMinimumSize(QtCore.QSize(100, 50))  
        self.pushButton_stop.setObjectName("pushButton_stop")  
        self.button_layout.addWidget(self.pushButton_stop)  
        # 将按钮布局添加到主布局  
        self.main_layout.addLayout(self.button_layout)  
        # 设置按钮区域的最小高度  
        self.main_layout.setStretch(0, 3)  # GIF区域占3份高度  
        self.main_layout.setStretch(1, 1)  # 按钮区域占1份高度  
        MainWindow.setCentralWidget(self.centralwidget)  
        self.retranslateUi(MainWindow)  
        QtCore.QMetaObject.connectSlotsByName(MainWindow)  
        self.pushButton_start.clicked.connect(self.start_loading)  
        self.pushButton_stop.clicked.connect(self.stop_loading)  
  
    def start_loading(self):  
        self.gif = QtGui.QMovie('loading.gif')  
        # 设置GIF缩放模式,保持比例适应标签大小  
        self.loading.setScaledContents(True)  
        self.loading.setMovie(self.gif)  
        self.gif.start()  
  
    def stop_loading(self):  
        if hasattr(self, 'gif'):  # 避免未启动时点击停止报错  
            self.gif.stop()  
            self.loading.clear()  
            self.loading.setScaledContents(False)  # 恢复默认状态  
  
    def retranslateUi(self, MainWindow):  
        _translate = QtCore.QCoreApplication.translate  
        MainWindow.setWindowTitle(_translate("MainWindow", "加载动画演示"))  
        self.pushButton_start.setText(_translate("MainWindow", "启动等待提示"))  
        self.pushButton_stop.setText(_translate("MainWindow", "停止等待提示"))  
  
  
import sys  
  
if __name__ == '__main__':  
    app = QtWidgets.QApplication(sys.argv)  
    MainWindow = QtWidgets.QMainWindow()  
    ui = Ui_MainWindow()  
    ui.setupUi(MainWindow)  
    MainWindow.show()  
    sys.exit(app.exec_())

Info: 说明 上面代码中使用QLabel类的setMovie()方法为其设置要显示的GIF动画图片,该方法要求有一个QMovie对象作为参数,QMovie类是QtGui模块中提供的一个用来显示简单且没有声音动画的类。

运行程序,单击启动等待提示按钮,将显示如图所示的运行效果;单击停止等待提示按钮,将自动关闭等待提示框。

loading.mp4

3  滑块:QSlider


PyQt5中提供了两个滑块控件,分别是水平滑块HorizontalSlider和垂直滑块VerticalSlider,但这两个滑块控件对应的类都是QSlider类,该类中提供了一个setOrientation()方法,通过设置该方法的参数,可以将滑块显示为水平或者垂直。

QSlider滑块类的常用方法及说明如表所示。

方    法说    明
setMinimum()设置滑块最小值
setMaximum()设置滑块最大值
setOrientation()设置滑块显示方向,取值如下:

◆ Qt.Horizontal:水平滑块

◆ Qt.Vertical:垂直滑块
setPageStep()设置步长值,通过鼠标点击滑块时使用
setSingleStep()设置步长值,通过鼠标拖动滑块时使用
setValue()设置滑块的值
setTickInterval()设置滑块的刻度间隔
setTickPosition()设置滑块刻度的标记位置,取值如下:

◆ QSlider.NoTicks:不显示刻度,这是默认设置

◆ QSlider.TicksBothSides:在滑块的两侧都显示刻度

◆ QSlider.TicksAbove:在水平滑块的上方显示刻度

◆ QSlider.TicksBelow:在水平滑块的下方显示刻度

◆ QSlider.TicksLeft:在垂直滑块的左侧显示刻度

◆ QSlider.TicksRight:在垂直滑块的右侧显示刻度
value()获取滑块的当前值

QSlider滑块类的常用信号及说明如表所示。

信    号说    明
valueChanged当滑块的值发生改变时发射该信号
sliderPressed当用户按下滑块时发射该信号
sliderMoved当用户拖动滑块时发射该信号
sliderReleased当用户释放滑块时发射该信号

Warning: 注意 QSlider滑块只能控制整数范围,因此它不适用于需要准确的大范围取值的场景。

实例 使用滑块改变刻度值及标签中的字体大小

在Qt Designer设计器中创建一个窗口,在窗口中分别添加一个HorizontalSlider水平滑块和一个VerticalSlider垂直滑块,然后添加一个HorizontalLayout水平布局管理器,在该布局管理器中添加一个Label标签,用来显示文字。设计完成后,保存为.ui文件,并使用Pyuic工具将其转换为.py代码文件。在.py文件中通过绑定水平滑块的valueChanged信号,实现拖动水平滑块时,实时改变垂直滑块的刻度值,同时改变Label标签中的字体大小。代码如下:

from PyQt5 import QtCore, QtGui, QtWidgets  
  
class Ui_MainWindow(object):  
  
    def setupUi(self, MainWindow):  
        MainWindow.setObjectName("MainWindow")  
        MainWindow.resize(313, 196)  
        self.centralwidget = QtWidgets.QWidget(MainWindow)  
        self.centralwidget.setObjectName("centralwidget")  
        # 创建水平滑块  
        self.horizontalSlider = QtWidgets.QSlider(self.centralwidget)  
        self.horizontalSlider.setGeometry(QtCore.QRect(20, 10, 231, 22))  
        self.horizontalSlider.setMinimum(8)         # 设置最小值为8  
        self.horizontalSlider.setMaximum(72)         # 设置最大值为72  
        self.horizontalSlider.setSingleStep(1)     # 设置通过鼠标拖动时的步长值  
        self.horizontalSlider.setPageStep(1)         # 设置通过鼠标点击时的步长值  
        self.horizontalSlider.setProperty("value", 8)    # 设置默认值为8  
        self.horizontalSlider.setOrientation(QtCore.Qt.Horizontal) # 设置滑块为水平滑块  
        # 设置在滑块上方显示刻度  
        self.horizontalSlider.setTickPosition(QtWidgets.QSlider.TicksAbove)  
        self.horizontalSlider.setTickInterval(3)     # 设置刻度的间隔  
        self.horizontalSlider.setObjectName("horizontalSlider")  
        # 创建垂直滑块  
        self.verticalSlider = QtWidgets.QSlider(self.centralwidget)  
        self.verticalSlider.setGeometry(QtCore.QRect(270, 20, 22, 171))  
        self.verticalSlider.setMinimum(8)         # 设置最小值为8  
        self.verticalSlider.setMaximum(72)         # 设置最大值为72  
        self.verticalSlider.setOrientation(QtCore.Qt.Vertical)     # 设置滑块为垂直滑块  
        self.verticalSlider.setInvertedAppearance(True)            # 设置刻度反方向显示  
        # 设置在滑块右侧显示刻度  
        self.verticalSlider.setTickPosition(QtWidgets.QSlider.TicksRight)  
        self.verticalSlider.setTickInterval(3)                     # 设置刻度的间隔  
        self.verticalSlider.setObjectName("verticalSlider")  
        # 创建一个水平布局管理器,主要用来放置显示文字的Label  
        self.horizontalLayoutWidget = QtWidgets.QWidget(self.centralwidget)  
        self.horizontalLayoutWidget.setGeometry(QtCore.QRect(20, 70, 251, 80))  
        self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")  
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)  
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)  
        self.horizontalLayout.setObjectName("horizontalLayout")  
        # 创建Label控件,用来显示文字  
        self.label = QtWidgets.QLabel(self.horizontalLayoutWidget)  
        self.label.setAlignment(QtCore.Qt.AlignCenter) # 设置文字居中对齐  
        self.label.setObjectName("label")  
        self.horizontalLayout.addWidget(self.label)       # 将Label添加到水平布局管理器中  
        MainWindow.setCentralWidget(self.centralwidget)  
        self.retranslateUi(MainWindow)  
        QtCore.QMetaObject.connectSlotsByName(MainWindow)  
        # 为水平滑块绑定valueChanged信号,在值发生更改时发射  
        self.horizontalSlider.valueChanged.connect(self.setfontsize)  
  
    # 定义槽函数,根据水平滑块的值改变垂直滑块的值和Label控件的字体大小  
    def setfontsize(self):  
        value = self.horizontalSlider.value()  
        self.verticalSlider.setValue(value)  
        self.label.setFont(QtGui.QFont("楷体", value))  
  
    def retranslateUi(self, MainWindow):  
        _translate = QtCore.QCoreApplication.translate  
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))  
        self.label.setText(_translate("MainWindow", "敢想敢为,注重细节"))  
  
import sys  
# 程序入口,程序从此处启动PyQt设计的窗体  
if __name__ == '__main__':  
   app = QtWidgets.QApplication(sys.argv)  
   MainWindow = QtWidgets.QMainWindow() # 创建窗体对象  
   ui = Ui_MainWindow()           # 创建PyQt设计的窗体对象  
   ui.setupUi(MainWindow)           # 调用PyQt窗体的方法对窗体对象进行初始化设置  
   MainWindow.show()               # 显示窗体  
   sys.exit(app.exec_())           # 程序关闭时退出进程

Info: 说明 上面代码中用到了水平布局管理器HorizontalLayout,它实质上是一个QHBoxLayout类的对象,它在这里的主要作用是放置Label控件,这样Label控件就只可以在水平布局管理器中显示,避免字体设置过大时,超出窗口范围的问题。

运行程序,默认效果如图所示,当用鼠标拖动水平滑块的刻度时,垂直滑块的刻度值会随之变化。另外,Label标签中的文字大小也会发生改变,如图所示。

  • 默认效果

Pasted image 20250901221002

  • 拖动水平滑块改变垂直滑块和字体大小

Pasted image 20250901221125