Я пишу программу, которая использует общий шаблон, который был преобразован из PDF в HTML для создания персонализированных отчетов для отдельных лиц. Чтобы преобразовать окончательные файлы HTML обратно в PDF, я использую PyQT5 и его метод printToPdf. Он прекрасно работает один раз, но программа зависает до тех пор, пока я не закрою открывающееся представление виджета, после чего оно завершает работу с ошибками и завершает всю программу Python. Как можно программно закрыть программу мирно, чтобы можно было рендерить весь HTML за один раз? Возможно, есть какой-то способ не утратить нить на виджет?

Вот мой текущий код.

for htmlFileAsString in files:

   app = QtWidgets.QApplication(sys.argv)
   loader = QtWebEngineWidgets.QWebEngineView()
   loader.setZoomFactor(1)
   loader.setHtml(htmlFileAsString)
   loader.page().pdfPrintingFinished.connect(
     lambda *args: print('finished:', args))
   def emit_pdf(finished):
     loader.show()
     loader.page().printToPdf('output/' + name + '/1.pdf')

   loader.loadFinished.connect(emit_pdf)
   app.exec()
0
TJohn2017 18 Окт 2019 в 01:26
Где loop?
 – 
eyllanesc
18 Окт 2019 в 03:07
Предоставленный мной фрагмент кода должен быть телом цикла, в котором каждый цикл преобразует новый файл html в pdf. Отредактирую, чтобы уточнить.
 – 
TJohn2017
18 Окт 2019 в 05:57

1 ответ

Как указано в ответе ekhumoro, проблема в том, что вы не можете создать несколько приложений QApplication (для получения дополнительных сведений необходимо просмотреть указанный ответ. ), поэтому, применив ту же технику, мы получим следующее решение:

import os
from PyQt5 import QtWidgets, QtWebEngineWidgets


class PdfPage(QtWebEngineWidgets.QWebEnginePage):
    def __init__(self):
        super().__init__()
        self._htmls_and_paths = []
        self._current_path = ""

        self.setZoomFactor(1)
        self.loadFinished.connect(self._handleLoadFinished)
        self.pdfPrintingFinished.connect(self._handlePrintingFinished)

    def convert(self, htmls, paths):
        self._htmls_and_paths = iter(zip(htmls, paths))
        self._fetchNext()

    def _fetchNext(self):
        try:
            self._current_path, path = next(self._htmls_and_paths)
        except StopIteration:
            return False
        else:
            self.setHtml(html)
        return True

    def _handleLoadFinished(self, ok):
        if ok:
            self.printToPdf(self._current_path)

    def _handlePrintingFinished(self, filePath, success):
        print("finished:", filePath, success)
        if not self._fetchNext():
            QtWidgets.QApplication.quit()


if __name__ == "__main__":

    current_dir = os.path.dirname(os.path.realpath(__file__))

    paths = []
    htmls = []
    for i in range(10):
        html = """<html>
    <header><title>This is title</title></header>
    <body>
    Hello world-{i}
    </body>
    </html>""".format(
            i=i
        )
        htmls.append(html)
        paths.append(os.path.join(current_dir, "{}.pdf".format(i)))

    app = QtWidgets.QApplication([])
    page = PdfPage()
    page.convert(htmls, paths)
    app.exec_()

    print("finished")
0
eyllanesc 18 Окт 2019 в 06:54
Спасибо. С небольшими изменениями это в основном работает. Вы знаете, есть ли способ не выдавать segfault, когда приложение готово? Я хотел бы продолжить работу в исходном скрипте Python, если это возможно. Кроме того, некоторые PDF-файлы (все из одного шаблона) отображаются только с фоновым изображением (без текста), и я не уверен, почему.
 – 
TJohn2017
18 Окт 2019 в 13:28