【问题标题】:How to show progress bar while saving file to excel in python?如何在python中将文件保存到excel时显示进度条?
【发布时间】:2020-06-03 13:06:00
【问题描述】:

如果你能帮助我,不胜感激。将文件保存到 Excel 时,我无法显示进度条。我想要实现的是在从pandas dataframe 也从qwidgettable 保存excel文件的同时显示一个进度条,因为它需要时间才能保存。在下载或保存 excel 文件之前,我希望该进度条关闭。我试着在网上查看,但我看不到我的查询的具体答案。到目前为止,这是我创建的编译代码。

import sys
from PyQt5 import QtWidgets, QtCore
import pandas as pd
import time
import psutil


class ThreadClass(QtCore.QThread):
   updateProgressBar = QtCore.pyqtSignal(int)

   def __init__(self, parent=None):
       super(ThreadClass, self).__init__(parent)

   def run(self):
       while True:
           val = int(psutil.cpu_percent())
           time.sleep(1)
           self.updateProgressBar.emit(val)

class Window(QtWidgets.QMainWindow):
    def __init__(self):
        super(Window, self).__init__()
        self.setGeometry(50,50,500,500)
        self.setWindowTitle('PyQt Tuts')
        self.table()

    def updateProgressBar(self, val):
        self.progressBar.setValue(val)

    def table(self):
        self.tableWidget = QtWidgets.QTableWidget()
        self.tableWidget.setGeometry(QtCore.QRect(220, 100, 411, 392))
        self.tableWidget.setColumnCount(2)
        self.tableWidget.setRowCount(5)
        self.tableWidget.show()

        item = QtWidgets.QTableWidgetItem()
        item.setText("Amount")
        self.tableWidget.setHorizontalHeaderItem(1, item)

        records = [
            ['Product 1', 1000],
            ['Product 2', 500],
            ['Product 3', 600],
            ['Product 4', 300],
            ['Product 5', 800],
        ]

        self.df = pd.DataFrame(records, columns=['Name', 'Amount'])

        for r in range(5):
            for c in range(2):
                table_item = str(self.df.iloc[r, c])
                self.tableWidget.setItem(r, c, QtWidgets.QTableWidgetItem(table_item))

        self.pb_extract = QtWidgets.QPushButton(self.tableWidget)
        self.pb_extract.setGeometry(QtCore.QRect(10, 200, 75, 23))
        self.pb_extract.clicked.connect(self.extract)
        self.pb_extract.setText("EXTRACT")
        self.pb_extract.show()

    def extract(self):
        self.lb_downloading = QtWidgets.QLabel(self.tableWidget)
        self.lb_downloading.setGeometry(QtCore.QRect(10, 270, 81, 16))
        self.lb_downloading.setText("Downloading..")
        self.lb_downloading.show()

        self.progressBar = QtWidgets.QProgressBar(self.tableWidget)
        self.progressBar.setGeometry(QtCore.QRect(10, 290, 171, 10))
        self.progressBar.show()

        self.threadclass = ThreadClass()
        self.threadclass.start()
        self.threadclass.updateProgressBar.connect(self.updateProgressBar)

        self.df.to_excel('Products.xlsx', index=False)
        print('Download complete!')

def run():
    app = QtWidgets.QApplication(sys.argv)
    app.setStyle("fusion")
    w = Window()
    sys.exit(app.exec_())

run()

这些代码如下所示:

我想要实现的是当我单击提取按钮时,下载进度条将关闭,直到 excel 文件完全下载/保存。

(附注:我只是得到val = int(psutil.cpu_percent()) 的随机值,因为我也不知道在应用程序运行时要使用什么特定代码/函数,只是为了向您显示我有一个正在移动的进度条。)

提前谢谢你!

【问题讨论】:

    标签: python excel pyqt pyqt5 qprogressbar


    【解决方案1】:

    这类问题在 SO 中被问过无数次,而且在 cmets 中也多次解释过需求,说明什么情况下可以,什么情况下不可以。所以为了避免重复同样的事情,我将根据OP的问题在这篇文章中解释这个主题。

    一个小部件通常用于显示和/或从用户那里获取信息,QProgressBar 做第一件事,也就是说,它显示进度信息,它不计算一下

    如果可以将任务细分为“n”个子任务,则可以计算进度,因为它相当于已经完成的子任务数相对于总子任务数。

    • 比如任务是上传一个N KB的文件到服务器,那么每个子任务可以有1KB的信息,所以进度是:

      progress = 100 * number_of_KB_submitted/number_of_KB_of_file
      
    • 另一个例子是如果你必须复制 n 个文件,那么进度是:

      progress = 100 * number_of_copied_files / number_of_total_files
      

    从上面可以看出,只有任务可以细分为子任务,才能计算进度,所以如果任务不能细分,就不可能计算任何进度。

    在将 pandas 保存在 excel 中的情况下,很明显它不能细分为“n”个任务,因此无法计算其进度。

    在使用 to_excel 将 pandas 保存在 excel 中的情况下,很明显它不能细分为“n”个任务,因此无法计算其进度。

    在这些情况下的解决方法是显示繁忙的 QProgressBar:

    progressbar.setRange(0, 0)
    

    在你的情况下:

    import sys
    from PyQt5 import QtWidgets, QtCore
    import pandas as pd
    import time
    
    import threading
    
    
    class ExcelWorker(QtCore.QObject):
        started = QtCore.pyqtSignal()
        finished = QtCore.pyqtSignal()
    
        def execute(self, df, filename):
            threading.Thread(target=self._execute, args=(df, filename), daemon=True).start()
    
        def _execute(self, df, filename):
            self.started.emit()
            df.to_excel(filename, index=False)
            self.finished.emit()
    
    
    class DownloaderProgressBar(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(DownloaderProgressBar, self).__init__(parent)
    
            self._progressbar = QtWidgets.QProgressBar()
    
            lay = QtWidgets.QVBoxLayout(self)
            lay.addWidget(QtWidgets.QLabel(self.tr("Downloading..")))
            lay.addWidget(self.progressbar)
    
        @property
        def progressbar(self):
            return self._progressbar
    
    
    class Window(QtWidgets.QMainWindow):
        def __init__(self):
            super(Window, self).__init__()
            self.setGeometry(50, 50, 500, 500)
            self.setWindowTitle("PyQt Tuts")
            self.create_table()
    
            self.create_progressbar()
            self.create_worker()
    
        def create_progressbar(self):
            self.downloader_progressbar = DownloaderProgressBar(self.tableWidget)
            self.downloader_progressbar.setGeometry(10, 270, 170, 80)
            self.downloader_progressbar.hide()
    
        def create_worker(self):
            self.worker = ExcelWorker()
            self.worker.started.connect(self.on_started)
            self.worker.finished.connect(self.on_finished)
    
        def create_table(self):
            self.tableWidget = QtWidgets.QTableWidget()
            self.tableWidget.setGeometry(QtCore.QRect(220, 100, 411, 392))
            self.tableWidget.setColumnCount(2)
            self.tableWidget.setRowCount(5)
            self.tableWidget.show()
    
            item = QtWidgets.QTableWidgetItem()
            item.setText("Amount")
            self.tableWidget.setHorizontalHeaderItem(1, item)
    
            records = [
                ["Product 1", 1000],
                ["Product 2", 500],
                ["Product 3", 600],
                ["Product 4", 300],
                ["Product 5", 800],
            ]
    
            self.df = pd.DataFrame(records, columns=["Name", "Amount"])
    
            for r in range(5):
                for c in range(2):
                    table_item = str(self.df.iloc[r, c])
                    self.tableWidget.setItem(r, c, QtWidgets.QTableWidgetItem(table_item))
    
            self.pb_extract = QtWidgets.QPushButton(self.tableWidget)
            self.pb_extract.setGeometry(QtCore.QRect(10, 200, 75, 23))
            self.pb_extract.clicked.connect(self.extract)
            self.pb_extract.setText("EXTRACT")
            self.pb_extract.show()
    
        def extract(self):
            self.worker.execute(self.df.copy(), "Products.xlsx")
            self.downloader_progressbar.show()
    
        @QtCore.pyqtSlot()
        def on_started(self):
            self.downloader_progressbar.progressbar.setRange(0, 0)
    
        @QtCore.pyqtSlot()
        def on_finished(self):
            self.downloader_progressbar.progressbar.setRange(0, 1)
    
    
    def run():
        app = QtWidgets.QApplication(sys.argv)
        app.setStyle("fusion")
        w = Window()
        sys.exit(app.exec_())
    
    
    run()
    

    【讨论】:

    • 谢谢您,先生!我还不熟悉进度条,老实说,我是编程新手。您对其目的进行了明确的解释。谢谢你!我只是想知道是否可以将时间作为进度条?那可能吗? “100 *时间通过/完成总时间”?谢谢!
    • @AlvinLorejas 你知道将 pandas 转换为 excel 需要多长时间吗?如果在转换过程中知道这一点,那么是的,否则就像你的情况一样:否。
    猜你喜欢
    • 2016-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-21
    • 2023-03-03
    • 1970-01-01
    相关资源
    最近更新 更多