python - 在 PyQt5 中为方法添加进度条
问题描述
我在这里有一个简单的 PyQt5 应用程序,可以从 Pdf 转换为 excel。当我单击按钮进行转换时,我想在下面的方法转换中添加一个进度条,因为它需要一些时间来执行,因此有一些可视化效果会很棒。
下面是我的代码:
我正在从 Qtdesigner 加载 ui。我还可以在可以附加到 pushButton_3 的某处添加进度条。进度条可以称为 'ProgressBar' 。请让我知道您如何完成它,因为这里的大多数答案并没有真正回答这个问题。
import sys
from PyQt5.QtWidgets import QMainWindow,QApplication,QTableView, QWidget, QFileDialog,QPushButton,QVBoxLayout,QMessageBox
from PyQt5 import uic
from PyPDF2 import PdfFileReader
from PyQt5 import QtCore,QtGui
import pandas as pd
import tabula
import re
from PandasModel import PandasModel
class App(QMainWindow):
def __init__(self):
QWidget.__init__(self)
uic.loadUi('designUI.ui',self)
self.pushButton.clicked.connect(self.openFileNameDialog)
self.pushButton_3.clicked.connect(self.convert)
self.pushButton_2.clicked.connect(self.view)
self.pushButton_4.clicked.connect(self.saveFileDialog)
def openFileNameDialog(self):
options = QFileDialog.Options()
options |= QFileDialog.DontUseNativeDialog
fileName, _ = QFileDialog.getOpenFileName(self,"Open File", "","All Files (*);;Python Files (*.py)")#, options=options)
if fileName:
self.file=fileName
def view(self):
model=PandasModel(self.converted_file)
self.tableView.setModel(model)
def convert(self):
self.converted_file=self.pdf2excel(self.file)
def saveFileDialog(self):
options = QFileDialog.Options()
options |= QFileDialog.DontUseNativeDialog
fileName, _ = QFileDialog.getSaveFileName(self, 'Save File', '', ".xls(*.xls)")
if fileName:
self.converted_file.to_excel(fileName)
msg=QMessageBox()
msg.setText('File is Saved')
msg.setStandardButtons(QMessageBox.Ok)
#msg.buttonClicked.connect(msgbtn)
msg.exec_()
def pdf2excel(self,pdf_file):
pdf = PdfFileReader(open(pdf_file,'rb'))
length=pdf.getNumPages()
result=pd.DataFrame(columns=['Department','Employment No','Employment Name',"Hire Date","Term Date","Birth Date",
"Seniority Date","Pay Code","FT/PT/S","Status"])
page=1
while page <= length:
df=tabula.read_pdf(pdf_file, pages = str(page),lattice =True, area=(75.775,16.0,572.715,779.29))[1:]
pattern = re.compile(r'(\s){2,}')
df=pd.DataFrame(df[df.columns[0]].replace(pattern,","))
df=df['Unnamed: 0'].str.split(",",expand=True)
df=df.rename(columns={0:'Department',
1:'Employment No',2:'Employment Name',3:"Hire Date",4:"Term Date",5:"Birth Date",
6:"Seniority Date",7:"Pay Code",8:"FT/PT/S",9:"Status"})
result=result.append(df,ignore_index=True)
page+=1
result["Hire Date"]=pd.to_datetime(result["Hire Date"])
result["Term Date"]=pd.to_datetime(result["Term Date"])
result["Days Difference"]=(result['Term Date']-result['Hire Date']).dt.days
result=result.dropna(how='all')
result=result.drop(columns=['Birth Date','Pay Code','Status'])
result=result[['Department','Employment No','Employment Name',"Hire Date","Term Date","Days Difference",
"Seniority Date","FT/PT/S"]]
return result
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setWindowIcon(QtGui.QIcon('pdf-to-excel-icon.png'))
ex = App()
ex.show()
sys.exit(app.exec_())
解决方案
首先,我建议验证变量是否存在或具有一定的大小,例如当尝试将您的代码与任何 pdf 一起使用时,您的代码已损坏。
回到问题,当你运行 pdf2excel 时,你会看到你不能改变窗口的大小,因为 GUI 被冻结了,所以它必须在另一个线程上运行,并通过信号将信息作为进度和数据帧发送。在这种情况下,我将创建一个 worker(QObject),它将存在于另一个具有 pdf2excel 函数的线程中。
import sys
from functools import partial
from PyQt5 import QtCore, QtGui, QtWidgets, uic
from PyPDF2 import PdfFileReader
import pandas as pd
import tabula
import re
from PandasModel import PandasModel
class PdfObject(QtCore.QObject):
progressChanged = QtCore.pyqtSignal(int)
maximumChanged = QtCore.pyqtSignal(int)
pandasChanged = QtCore.pyqtSignal(pd.DataFrame)
@QtCore.pyqtSlot(str)
def pdf2excel(self, pdf_file):
pdf = PdfFileReader(open(pdf_file, "rb"))
length = pdf.getNumPages()
result = pd.DataFrame(
columns=[
"Department",
"Employment No",
"Employment Name",
"Hire Date",
"Term Date",
"Birth Date",
"Seniority Date",
"Pay Code",
"FT/PT/S",
"Status",
]
)
self.maximumChanged.emit(length)
page = 1
while page <= length:
self.progressChanged.emit(page)
df = tabula.read_pdf(
pdf_file,
pages=str(page),
lattice=True,
area=(75.775, 16.0, 572.715, 779.29),
)[1:]
pattern = re.compile(r"(\s){2,}")
df = pd.DataFrame(df[df.columns[0]].replace(pattern, ","))
df = df["Unnamed: 0"].str.split(",", expand=True)
df = df.rename(
columns={
0: "Department",
1: "Employment No",
2: "Employment Name",
3: "Hire Date",
4: "Term Date",
5: "Birth Date",
6: "Seniority Date",
7: "Pay Code",
8: "FT/PT/S",
9: "Status",
}
)
result = result.append(df, ignore_index=True)
page += 1
result["Hire Date"] = pd.to_datetime(result["Hire Date"])
result["Term Date"] = pd.to_datetime(result["Term Date"])
result["Days Difference"] = (
result["Term Date"] - result["Hire Date"]
).dt.days
result = result.dropna(how="all")
result = result.drop(columns=["Birth Date", "Pay Code", "Status"])
result = result[
[
"Department",
"Employment No",
"Employment Name",
"Hire Date",
"Term Date",
"Days Difference",
"Seniority Date",
"FT/PT/S",
]
]
self.pandasChanged.emit(result)
class App(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(App, self).__init__(parent)
uic.loadUi("designUI.ui", self)
self.filename = ""
self.converted_file = None
thread = QtCore.QThread(self)
thread.start()
self.pdf_object = PdfObject()
self.pdf_object.moveToThread(thread)
self.pdf_object.maximumChanged.connect(self.progressBar.setMaximum)
self.pdf_object.progressChanged.connect(self.progressBar.setValue)
self.pdf_object.pandasChanged.connect(self.on_pandasChanged)
self.pushButton.clicked.connect(self.openFileNameDialog)
self.pushButton_3.clicked.connect(self.convert)
self.pushButton_2.clicked.connect(self.view)
self.pushButton_4.clicked.connect(self.saveFileDialog)
def openFileNameDialog(self):
options = QtWidgets.QFileDialog.Options()
options |= QtWidgets.QFileDialog.DontUseNativeDialog
fileName, _ = QtWidgets.QFileDialog.getOpenFileName(
self, "Open File", "", "All Files (*);;Python Files (*.py)"
) # , options=options)
if fileName:
self.filename = fileName
def view(self):
if self.converted_file is not None:
model = PandasModel(self.converted_file)
self.tableView.setModel(model)
def convert(self):
if self.filename:
wrapper = partial(self.pdf_object.pdf2excel, self.filename)
QtCore.QTimer.singleShot(0, wrapper)
@QtCore.pyqtSlot(pd.DataFrame)
def on_pandasChanged(self, df):
self.converted_file = df.copy()
def saveFileDialog(self):
options = QtWidgets.QFileDialog.Options()
options |= QtWidgets.QFileDialog.DontUseNativeDialog
fileName, _ = QtWidgets.QFileDialog.getSaveFileName(
self, "Save File", "", ".xls(*.xls)"
)
if fileName and self.converted_file is not None:
self.converted_file.to_excel(fileName)
msg = QtWidgets.QMessageBox()
msg.setText("File is Saved")
msg.setStandardButtons(QtWidgets.QMessageBox.Ok)
# msg.buttonClicked.connect(msgbtn)
msg.exec_()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
app.setWindowIcon(QtGui.QIcon("pdf-to-excel-icon.png"))
ex = App()
ex.show()
sys.exit(app.exec_())
推荐阅读
- r - 使用 R 读取 Microsoft Project 文件 (.mpp)?
- angular - 通过在 Angular 中返回字符串而不是 Observable 来消除 subscribe(...)
- python - 错误:命令出错,退出状态为 1:python setup.py egg_info 检查日志以获取完整的命令输出。
- reactjs - ReactJS - 从条形码图像组件中获取 base64 字符串
- python - 如果 dict.key 等于同一父节点中的其他 XML 节点,则将 ET.SubElement.text 设置为 dict.value
- gitlab - Gitlab:通过 API 列出 MR 中所有更改的文件
- python - RuntimeError at / cannot cache function '__shear_dense': no locator available for file '/home/...site-packages/librosa/util/utils.py'
- visual-studio-code - VS Code - 与 VPS 同步:添加文件/重命名/删除
- ruby-on-rails - 旧版本/不存在版本上的 Ruby 搜索模板
- vue.js - 字体真棒Unicode(NUXT)