如何在 python 中将文件保存到 excel 时显示进度条?
How to show progress bar while saving file to excel in python?
如果你能帮助我,我将不胜感激。将文件保存到 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 文件完全 downloaded/saved。
(P.S 我只是得到 val = int(psutil.cpu_percent())
的随机值,因为我也不知道在应用 运行 时要使用什么特定的 code/function 只是为了显示告诉你我有一个进度条在移动。)
提前致谢!
这类问题在SO里被问过无数次了,很多时候需求都在评论里说明什么情况下可以,什么情况下不可以。所以为了避免重复同样的事情,我将根据OP的问题在post中解释这个话题。
widget一般是用来显示and/or从用户那里获取的信息,而QProgressBar做的第一件事就是显示进度信息, 它不计算它。
如果任务可以细分为"n"个子任务,就可以计算进度,因为它相当于已经完成的子任务数占总子任务数的比值。
比如任务是上传一个NKB的文件到服务器,那么每个子任务可以是1KB的信息,那么进度就是:
progress = 100 * number_of_KB_submitted/number_of_KB_of_file
再比如你要复制n个文件,那么进度就是:
progress = 100 * number_of_copied_files / number_of_total_files
从上面可以看出,只有任务可以细分为子任务才能计算进度,所以如果任务不能细分,就无法计算任何进度。
在一个excel中保存pandas的情况下,显然无法再细分为"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()
如果你能帮助我,我将不胜感激。将文件保存到 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 文件完全 downloaded/saved。
(P.S 我只是得到 val = int(psutil.cpu_percent())
的随机值,因为我也不知道在应用 运行 时要使用什么特定的 code/function 只是为了显示告诉你我有一个进度条在移动。)
提前致谢!
这类问题在SO里被问过无数次了,很多时候需求都在评论里说明什么情况下可以,什么情况下不可以。所以为了避免重复同样的事情,我将根据OP的问题在post中解释这个话题。
widget一般是用来显示and/or从用户那里获取的信息,而QProgressBar做的第一件事就是显示进度信息, 它不计算它。
如果任务可以细分为"n"个子任务,就可以计算进度,因为它相当于已经完成的子任务数占总子任务数的比值。
比如任务是上传一个NKB的文件到服务器,那么每个子任务可以是1KB的信息,那么进度就是:
progress = 100 * number_of_KB_submitted/number_of_KB_of_file
再比如你要复制n个文件,那么进度就是:
progress = 100 * number_of_copied_files / number_of_total_files
从上面可以看出,只有任务可以细分为子任务才能计算进度,所以如果任务不能细分,就无法计算任何进度。
在一个excel中保存pandas的情况下,显然无法再细分为"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()