PyQt5 在 class' 方法中调用静态方法会打乱方法代码的执行顺序

PyQt5 Calling a static method inside a class' method messes up the execution order of the method's code

过去几天我一直在为 GUI 使用 PyQt5 构建一个相当简单的程序,但我遇到了以下问题,我似乎找不到解决方案。

这是我的代码的一个过于简化的版本(为了简短起见,保留了绝对的基础知识):

def run_blueprint(file):
    # doing stuff to the file and returning the path to the output file
    return full_path


class Window(QMainWindow, Ui_MainWindow):
    # some variables here

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

    def connectSignalsSlots(self):
        self.pushButton.clicked.connect(self.processFiles)

    def processFiles(self):
        self.toggleElements()
        for i, file in enumerate(self.selected_files_directories):
            temp_full_path = run_blueprint(file)
            self.listWidget_3.insertItem(i, temp_full_path)
        self.toggleElements()

    def toggleElements(self):
        self.pushButton_2.setEnabled(not self.pushButton_2.isEnabled())
        self.listWidget.setEnabled(not self.listWidget.isEnabled())


if __name__ == "__main__":
    app = QApplication(sys.argv)
    win = Window()
    win.show()
    sys.exit(app.exec())

假设我已经 select 编辑了 listWidget 中的一个项目,并且还在 selected_files_directories[] 变量中存储了一个文件路径列表。

如果我按原样 运行 代码,当 processFiles(self) 到 运行 时,我会遇到一些奇怪的行为。由于某种原因,for 循环首先是 运行,然后是第一个 toggleElements(),然后是第二个 toggleElements()。这导致我想暂时禁用这两个元素,直到 for 循环结束并一直保持启用状态。

但是,如果我根本不调用 run_blueprint(file) 方法,而是 运行 for 循环内的任何其他代码,甚至完全放弃循环,那么这两个元素将首先被禁用,然后是其余代码 运行s,最后它们再次启用。

我认为问题与我在 class 之外调用静态方法有关。你对如何解决这个问题有什么想法吗?提前致谢!


编辑: 下面是 run_blueprint() 函数的简化版本。 该程序的基本功能如下:我 select 模板文件 (.docx) 和输入文件 (.pdf)。然后使用 docxtplpdfplumber 库,对于每个 selected 输入文件,我从中获取特定的文本片段并将它们放在模板文档中并将其另存为 .docx 文件.

在下面的代码中,假设 template_pathbp_path 分别显示模板文件和蓝图文件的路径。

def run_blueprint(file):
    doc = DocxTemplate(template_path) # docxtpl method
    global lns
    lns = export_data(file) # function I made that uses pdfplumber to get all the text from a pdf file

    global context
    context = {}

    with open(bp_path, 'r', encoding='utf8') as f:
        blueprint = f.read() # blueprint contains python code that populates the context variable. I do it this way to easily change between blueprints
    exec(blueprint, globals(), locals()) # I know it's not a good practice to use exec but it's intended for personal use

    doc.render(context) # docxtpl method
    output_path = "D:\Desktop" # could be any path
    doc.save(output_path) # docxtpl method
    return output_path

蓝图代码通常包含 API 调用,需要几毫秒才能发送响应。除此之外,它主要 regex 用于定位我正在寻找的文本片段。

这是重绘 canvas 的问题。在 toggleElements 调用之后添加一个 repaint 调用。

def processFiles(self):
    self.toggleElements()
    self.repaint()
    
    for i, file in enumerate(self.selected_files_directories):
        temp_full_path = run_blueprint(file)
        self.listWidget_3.insertItem(i, temp_full_path)
    
    self.toggleElements()

根据@musicamante 的评论建议获取更多上下文并帮助澄清: 重绘 canvas 没有问题。问题是函数阻塞了主线程。根据上下文,更好的解决方案是将阻塞任务卸载到 QThread or QProcess 以解锁主线程。