简体   繁体   English

如何在 python 中将文件保存到 excel 时显示进度条?

[英]How to show progress bar while saving file to excel in python?

Appreciate if you could help me.感谢您能帮助我。 I have a trouble showing up the progress bar while saving file to excel.将文件保存到 excel 时无法显示进度条。 What I want to achieve is to show a progress bar while saving excel file from a pandas dataframe also from qwidgettable as it takes time before it saves.我想要实现的是在从pandas dataframe qwidgettable保存 excel 文件的同时显示进度条,因为它需要时间才能保存。 Until the excel file is downloaded or saved i want that progress bar to close.在下载或保存 excel 文件之前,我希望该进度条关闭。 I tried looking over the net but I cant see specific answers to my query.我试着在网上查看,但我看不到我的查询的具体答案。 So far, this is the compiled codes I have created.到目前为止,这是我创建的编译代码。

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()

these codes look like this:这些代码如下所示:

在此处输入图像描述

what i want to achieve is when i click the extract button, the downloading progressbar will close until the excel file fully downloaded/saved.我想要实现的是当我单击提取按钮时,下载进度条将关闭,直到 excel 文件完全下载/保存。

(PS i just get random values for val = int(psutil.cpu_percent()) because i also don't know what specific code/function to use while the app is running just to show to you that i have a progress bar moving.) (PS 我只是得到val = int(psutil.cpu_percent())的随机值,因为我也不知道在应用程序运行时要使用什么特定代码/函数,只是为了向您显示我有一个进度条在移动。 )

Thank you in advance!先感谢您!

These types of questions have been asked countless times in SO, and many times the requirements have been explained in the comments explaining in which case it is possible, and in which cases it is not possible.这些类型的问题在 SO 中已经被问过无数次,并且在评论中已经多次解释了这些要求,解释了在哪种情况下可以,在哪些情况下不可以。 So to avoid repeating the same thing, I will explain this topic in this post based on the OP's question.所以为了避免重复同样的事情,我将根据 OP 的问题在这篇文章中解释这个主题。

A widget in general is used to show and/or obtain information from the user, and a QProgressBar does the first thing, that is, it shows the progress information, it does not calculate it .一个小部件通常用于显示和/或从用户那里获取信息,QProgressBar 做第一件事,即显示进度信息,它不计算它

Progress can be calculated if the task can be subdivided into "n" subtasks, since it would be equivalent to the number of subtasks already done with respect to the number of total subtasks.如果可以将任务细分为“n”个子任务,则可以计算进度,因为它相当于已经完成的子任务数量相对于总子任务的数量。

  • For example if the task is to upload a N KB file to a server, then each subtask can be 1KB of information, so the progress would be:例如,如果任务是上传一个 N KB 文件到服务器,那么每个子任务可以是 1KB 的信息,所以进度为:

     progress = 100 * number_of_KB_submitted/number_of_KB_of_file
  • Another example would be if you have to copy n files, then the progress would be:另一个例子是如果你必须复制 n 个文件,那么进度是:

     progress = 100 * number_of_copied_files / number_of_total_files

From the above it is obvious that progress can only be calculated if the task can be subdivided into subtasks, so if the task cannot be subdivided then it is impossible to calculate any progress.从上面可以看出,只有任务可以细分为子任务,才能计算进度,所以如果任务不能细分,就不可能计算任何进度。

In the case of saving the pandas in an excel it is obvious that it cannot be subdivided into "n" tasks so it will be impossible to calculate its progress.在将 pandas 保存在 excel 中的情况下,显然不能将其细分为“n”个任务,因此无法计算其进度。

In the case of saving the pandas in an excel using to_excel it is obvious that it cannot be subdivided into "n" tasks so it will be impossible to calculate its progress.在使用 to_excel 将 pandas 保存在 excel 中的情况下,很明显它不能细分为“n”个任务,因此无法计算其进度。

A workaround in those cases is to show a busy QProgressBar:在这些情况下的解决方法是显示一个繁忙的 QProgressBar:

progressbar.setRange(0, 0)

In your case:在你的情况下:

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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM