在PyQt5中为一个方法添加进度条

3
我这里有一个简单的PyQt5应用程序,可以将PDF转换为Excel。我想在下面convert方法中添加一个进度条,以便在单击按钮进行转换时能够更直观地显示执行进度,因为这需要一些时间来执行,所以拥有可视化效果会很好。
以下是我的代码:
我正在从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_())  

1个回答

4
首先,我建议进行变量存在性或特定大小的验证,例如在尝试将代码用于任何PDF时,您的代码会崩溃。
就问题而言,当您运行pdf2excel时,您会发现无法更改窗口的大小,因为GUI已经冻结,所以它必须在另一个线程上运行,并通过信号发送进度和dataframe信息。 在这种情况下,我会创建一个位于另一个线程中具有pdf2excel函数的worker(QObject)。
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_())

谢谢您的回答!我不能提供PDF文件,因为它包含一些机密信息。此外,当我按下pushButton_3时,我从上面的代码中得到了这个错误!TypeError: QTimer(parent: QObject = None): argument 1 has unexpected type 'int' - Kartikeya Sharma
@KartikeyaSharma 我已经纠正了它,因为我无法测试它,因为所需的PDF非常特殊。请再试一次。 - eyllanesc
谢谢,进度条现在可以工作了,但变量self.converted_file始终设置为None。它没有像我的代码中那样改变为获取的数据帧。请帮忙。 - Kartikeya Sharma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接