PyQt5循环问题,仅QWebEngineView对象的最后一次迭代有效

时间:2018-11-13 09:38:41

标签: python pyqt pyqt5

我没有使用Qt / PyQt的经验。 我只是想将PyQt用于Web引擎功能,以将html文件的文件夹“转换”为pdf文档。

如果只有1个html文件,则代码运行良好,但是,当有多个html文件时,它仅为循环中的最后一个文件生成pdf

我认为问题必须与Qt内容,循环,事件等有关-但我不知道从哪里开始进行解决。如您所知,我只是Qt来生成html-> pdf,我对构建GUI并不感兴趣。

我了解到在循环结束时使用QApplication.processEvents()可能会解决此问题,但是结果是相同的。 我尝试在代码中添加睡眠/暂停,同样。

import sys
import os

from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import QDir, QUrl

# read somewhere this is needed to load local html, works without for me though
sys.argv.append("--disable-web-security")
app = QApplication(sys.argv)

iter_num = 0

directory = 'my_webfile_directory'
for filename in os.listdir(directory):
    if filename.endswith(".htm") or filename.endswith(".html"):
        with open(os.path.join(directory, filename), 'r') as myfile:

            print(filename)
            raw_html = myfile.read()
            # init qt web view
            view = QWebEngineView()
            view.setHtml(raw_html)

            # set to close web view after pdf is created
            view.page().pdfPrintingFinished.connect(view.close)
            # generate filename
            iter_num += 1
            outputfilename = str(iter_num) + ".pdf"
            outputfullpath = os.path.join(directory, outputfilename)

            def save_pdf(finished):
                view.page().printToPdf(outputfullpath)
            # when web view is ready, save the pdf
            view.loadFinished.connect(save_pdf)
            # QApplication.processEvents()

app.exec()

1 个答案:

答案 0 :(得分:1)

我认为QWebEngineView不是线程安全的,因为我能够通过创建要处理的文件队列并使用信号依次执行一个文件来使其始终如一地工作,这是一个演示应用程序: / p>

import sys
import os

from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import QObject, QDir, QUrl, pyqtSignal


class HtmlToPdfConverter(QObject):

    queueProcessed = pyqtSignal()

    def __init__(self):
        super().__init__()

        self._queue = []
        self._current = None

    def queue(self, html_file, output_file):
        self._queue.append((html_file, output_file))

    def process_queue(self):
        if self._queue:
            raw_html = ''
            self._current = self._queue.pop(0)
            with open(self._current[0], 'r') as my_file:
                raw_html = my_file.read()

            view = QWebEngineView()
            view.loadFinished.connect(self._get_load_finished_event(view))
            view.page().pdfPrintingFinished.connect(self._get_printing_finished_event(view))
            view.setHtml(raw_html)
        else:
            self.queueProcessed.emit()

    def _get_load_finished_event(self, view):
        def _load_finished(success):
            if success:
                view.page().printToPdf(self._current[1])
        return _load_finished

    def _get_printing_finished_event(self, view):
        def _printing_finished(file, success):
            view.close()
            self.process_queue()
        return _printing_finished


class App(QApplication):
    def __init__(self, sys_argv):
        super().__init__(sys_argv)

        self.dummy_window = QMainWindow()
        self.dummy_window.show()

    def generate_pdfs(self, directory):
        converter = HtmlToPdfConverter()
        converter.queueProcessed.connect(self._queue_processed)

        iter_num = 0

        for filename in os.listdir(directory):
            if filename.endswith(".htm") or filename.endswith(".html"):
                iter_num += 1
                out_filename = os.path.join(directory, str(iter_num) + ".pdf")
                converter.queue(os.path.join(directory, filename), out_filename)

        converter.process_queue()

    def _queue_processed(self):
        QMessageBox.information(self.dummy_window, 'Pdf Generator', 'All PDF files have been generated.')


if __name__ == '__main__':
    app = App(sys.argv)
    app.generate_pdfs('c:/temp/test')

    sys.exit(app.exec_())