基于pyqt5 构建弹窗进度条,在大型计算中实时显示进度

       在大型计算时(例如神经网络训练),经常会遇到计算时间过长,无法知道当前的计算进度,无法判断程序是否进入死循环等问题。采用进度条可以在一定程度上了解当前进度,判断后续所需的计算时间,缓解等待过程中的焦虑。在计算进程中可以放心地去干其他事情。

1.常规进度条

       常规的方法是使用打印字符的形式展示当前的进度,但这一类进度条很容易被淹没在其他需要显示的内容中,使用起来比较繁琐,想要知道多个任务进行到了第几个了还要从打印历史中手动查看。字符进度显示的例子如下:

计算进度:|>>>>>>>>>>>>>>>>>>>>>>>>>>>>>| 100.0%

2.GUI进度条

       最为合适的方法是创建弹窗进度条,在弹窗中实时显示当前进行的子任务及子任务执行的进度。

  

        基于pycharm+pyqt5 实现的弹窗进度条的效果如下,pyqt5 的安装请搜索其他案例,在此不具体介绍了。

  

        填坑:请注意在pyqt5图形设计界面中生成的python代码直接运行时会出现卡顿,直到进度条到达100%后才显示的情况。这是因为没有设置窗口刷新,请在设置好进度值之后使用 QApplication.processEvents() 进行窗口的刷新,简单易行,对于间隔时间较短的情况无需建立两个线程进行通信。

       不想了解上述坑的同学,可以直接使用如下简单易用的代码,将其放在自己的用户包中,随时调用(喜欢和认为有用朋友可以给我点个赞!):

# _*_coding: UTF-8_*_
# 开发作者 :TXH
# 开发时间 :2020-09-08 10:20
# 文件名称 :Qt_Processbar.py
# 开发工具 :Python 3.7 + Pycharm IDE

from PyQt5.QtWidgets import QApplication, QWidget, QDialog, QLabel, QLineEdit, QProgressBar, \
    QPushButton, QVBoxLayout, QHBoxLayout, QGridLayout, QDialogButtonBox
from PyQt5.QtCore import Qt, QBasicTimer, QThread,QRect
import sys


class ProgressBar(QDialog):
    def __init__(self,  parent=None):
        super(ProgressBar, self).__init__(parent)

        # Qdialog窗体的设置
        self.resize(500, 32) # QDialog窗的大小

        # 创建并设置 QProcessbar
        self.progressBar = QProgressBar(self) # 创建
        self.progressBar.setMinimum(0) #设置进度条最小值
        self.progressBar.setMaximum(100)  # 设置进度条最大值
        self.progressBar.setValue(0)  # 进度条初始值为0
        self.progressBar.setGeometry(QRect(1, 3, 499, 28)) # 设置进度条在 QDialog 中的位置 [左,上,右,下]
        self.show()

    def setValue(self,task_number,total_task_number, value): # 设置总任务进度和子任务进度
        if task_number=='0' and total_task_number=='0': 
            self.setWindowTitle(self.tr('正在处理中'))
        else:
            label = "正在处理:" + "第" + str(task_number) + "/" + str(total_task_number)+'个任务'
            self.setWindowTitle(self.tr(label)) # 顶部的标题
        self.progressBar.setValue(value)

class pyqtbar():
    '''
    task_number和 total_task_number都为 0 时,不显示当前进行的任务情况
    task_number<total_task_number 都为整数,错误的设置将出现错误显示,暂未设置报错警告
    
    # 使用示例
    import time
    bar = pyqtbar() # 创建实例
    total_number=10
    # 任务1
    task_id=1
    for process in range(1, 100):
        time.sleep(0.05)
        bar.set_value(task_id,total_number,process) # 刷新进度条
    # 任务2
    task_id = 2
    for process in range(1, 100):
        time.sleep(0.05)
        bar.set_value(task_id, total_number,process)

    bar.close # 关闭 bar 和 app

    '''
    def __init__(self):
        self.app = QApplication(sys.argv) # 打开系统 app
        self.progressbar = ProgressBar() # 初始化 ProcessBar实例

    def set_value(self,task_number,total_task_number,i):
        self.progressbar.setValue(str(task_number), str(total_task_number),i + 1)  # 更新进度条的值
        QApplication.processEvents()  # 实时刷新显示

    @property
    def close(self):
        self.progressbar.close()  # 关闭进度条
        self.app.exit() # 关闭系统 app

if __name__ == '__main__':

    import time
    # 使用示例
    bar=pyqtbar() # 创建实例
    total_number=10 # 总任务数
    # 任务1
    task_id=1 # 子任务序号
    for process in range(1, 100):
        time.sleep(0.05)
        bar.set_value(task_id,total_number,process) # 刷新进度条
    # 任务2
    task_id = 2
    for process in range(1, 100):
        time.sleep(0.05)
        bar.set_value(task_id, total_number,process)

    bar.close # 关闭 bar 和 app

3.多线程进度条方案(用于单步耗时较高的情况)

        对于时长超过5秒的高耗时迭代计算,第2节的方案会出现卡顿,在此给出使用多线程进行计算的方案。其中需要:1.将要运行的代码块构建成 Qthread 类(子线程),在Qthread实例中不断将单个任务进度和总的任务进度通过pyqtSignal功能发送给主线程;2.pyqtbar()类在初始化时需要传入上述Qthread实例。后续主线程根据子线程发送的信号进行更新,不会出现卡顿的情况。

踩坑:在Qthread 代码块中不要使用基于pyqt5 的matplotlib 绘图功能,否则整个程序将卡在绘图代码处。

# _*_coding: UTF-8_*_
# 开发作者 :TXH
# 开发时间 :2020/9/14 1:44
# 文件名称 :pyqtbar.py
# 开发工具 :Python 3.7+ Pycharm IDE



from PyQt5 import QtWidgets, QtCore
import sys
from PyQt5.QtCore import *
import time


class ProcessBar(QtWidgets.QWidget):

    def __init__(self,work):
        super().__init__()
        self.work=work
        self.run_work()


    def run_work(self):
        # 创建线程
        # 连接信号
        self.work._signal.connect(self.call_backlog)  # 进程连接回传到GUI的事件
        # 开始线程
        self.work.start()

        # 进度条设置
        self.pbar = QtWidgets.QProgressBar(self)
        self.pbar.setMinimum(0)  # 设置进度条最小值
        self.pbar.setMaximum(100)  # 设置进度条最大值
        self.pbar.setValue(0)  # 进度条初始值为0
        self.pbar.setGeometry(QRect(1, 3, 499, 28))  # 设置进度条在 QDialog 中的位置 [左,上,右,下]

        # 窗口初始化
        self.setGeometry(300, 300, 500, 32)
        self.setWindowTitle('正在处理中')
        self.show()
        # self.work = None  # 初始化线程

    def call_backlog(self, msg,task_number,total_task_number):
        if task_number==0 and total_task_number==0:
            self.setWindowTitle(self.tr('正在处理中'))
        else:
            label = "正在处理:" + "第" + str(task_number) + "/" + str(total_task_number)+'个任务'
            self.setWindowTitle(self.tr(label)) # 顶部的标题
        self.pbar.setValue(int(msg))  # 将线程的参数传入进度条

class pyqtbar():
    def __init__(self,work):
        self.app = QtWidgets.QApplication(sys.argv)
        self.myshow = ProcessBar(work)
        self.myshow.show()
        sys.exit(self.app.exec_())


if __name__ == "__main__":
    # 继承QThread
    class Runthread(QThread):
        #  通过类成员对象定义信号对象
        _signal = pyqtSignal(int,int,int)

        def __init__(self):
            super(Runthread, self).__init__()

        def run(self):        
            task_number = 0
            total_task_number = 9    
            for i in range(100):
                ##########################
                #                        #
                #将需要计算的代码块放在此处#
                #                        #
                ##########################

                time.sleep(0.1)
                self._signal.emit(i + 1,task_number ,total_task_number )  # 发送实时任务进度和总任务进度

    work = Runthread()
    bar=pyqtbar(work)

 

 

 

 

  • 37
    点赞
  • 127
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
下面是使用 PyQt5 和 tqdm 模块实现的更新进度条示例代码: ```python import sys from PyQt5.QtWidgets import QApplication, QWidget, QProgressBar, QPushButton from PyQt5.QtCore import QThread, pyqtSignal from tqdm import tqdm class ProgressThread(QThread): progress_signal = pyqtSignal(int) def __init__(self, total): super().__init__() self.total = total def run(self): for i in tqdm(range(self.total)): self.progress_signal.emit(i) class ProgressBar(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setGeometry(100, 100, 300, 100) self.setWindowTitle('Progress Bar') self.progress_bar = QProgressBar(self) self.progress_bar.setGeometry(20, 20, 260, 20) self.start_button = QPushButton('Start', self) self.start_button.setGeometry(20, 60, 75, 23) self.start_button.clicked.connect(self.start_progress) self.stop_button = QPushButton('Stop', self) self.stop_button.setGeometry(100, 60, 75, 23) self.stop_button.clicked.connect(self.stop_progress) self.show() def start_progress(self): self.thread = ProgressThread(100) self.thread.progress_signal.connect(self.update_progress) self.thread.start() def stop_progress(self): self.thread.terminate() def update_progress(self, value): self.progress_bar.setValue(value) if __name__ == '__main__': app = QApplication(sys.argv) bar = ProgressBar() sys.exit(app.exec_()) ``` 这个示例程序创建了一个简单的窗口,包含一个进度条和两个按钮。当用户点击“Start”按钮时,程序将启动一个后台线程来执行进度条更新任务。当用户点击“Stop”按钮时,程序将停止后台线程。进度条更新任务使用 tqdm 模块来显示进度条。通过使用 pyqtSignal,我们可以在后台线程和主线程之间进行通信,从而实现进度条的更新。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

txh3093

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值