I have this demo program that is not working as I would wish:
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtPrintSupport import *
from PyQt5.QtWebEngineWidgets import *
class Runnable(QRunnable):
def __init__(self, window, mode):
super(Runnable, self).__init__()
self.window = window
self.mode = mode
self.html = '<!DOCTYPE HTML><html><body><p>test</p></body></html>'
self.report_filename = 'report.pdf'
def run(self):
if self.mode == 'sync':
# this works ok
printer = QPrinter()
printer.setOutputFormat(QPrinter.PdfFormat)
printer.setPaperSize(QPrinter.A4)
printer.setOutputFileName(self.report_filename)
doc = QTextDocument()
doc.setHtml(self.html)
#doc.setPageSize(printer.pageRect().size())
doc.print(printer)
print('pdf file created')
elif self.mode == 'async':
# this doesn't work
self.page = QWebEnginePage()
self.page.loadFinished.connect(self.on_load_finished)
loadFinished_works_for_setHtml = False
if loadFinished_works_for_setHtml:
# async func, but no loadFinished signal in docs, too bad
self.page.setHtml(self.html)
else:
# silly, all because no loadFinished signal for setHtml()
with open('report.html', 'w', encoding='utf-8') as f:
f.write(self.html)
url = QUrl('file:report.html')
print('url.isLocalFile():', url.isLocalFile())
self.page.load(url)
def on_load_finished(self, ok):
# 1. problem: This method never executes, why?
# I tried with QWebEngineView() too, but without luck.
# 2. problem: If this method somehow executes, it will run in main thread,
# but self.page.printToPdf() can be slow, so I want this to also
# run in runnable thread or some other thread, but not in main thread
print('load finished, ok: ', ok)
#self.page.pdfPrintingFinished.connect(self.on_pdf_printing_finished)
#page_layout = QPageLayout(QPageSize(QPageSize.A4), QPageLayout.Portrait, QMarginsF(20, 20, 20, 20), QPageLayout.Millimeter, minMargins = QMarginsF(0, 0, 0, 0))
#self.page.printToPdf(self.report_filename, page_layout)
#def on_pdf_printing_finished(self, file_path, ok):
# print('printToPdf finished', file_path, ok)
# # send signal to main thread or open pdf file with subprocess.Popen() or sth.
# # 1a. problem: I want this (for example opening pdf file) to also run in
# # runnable thread or some other thread, but not in main thread
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.print_sync_button = QPushButton('Make PDF (sync)', self)
self.print_async_button = QPushButton('Make PDF (async)', self)
self.print_sync_button.clicked.connect(lambda : self.handle_print('sync'))
self.print_async_button.clicked.connect(lambda : self.handle_print('async'))
layout = QHBoxLayout(self)
layout.addWidget(self.print_sync_button)
layout.addWidget(self.print_async_button)
def handle_print(self, mode='sync'):
worker = Runnable(self, mode)
QThreadPool.globalInstance().start(worker)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
I described my problems in comments (1., 1a., 2.) in code.
My first problem is that self.page.load(url) never sends a signal loadFinished. I don't know why?
The second problem is more general: how to run async code in QRunnable run() method (if it is at all possible)? For example, I want to generate pdf report with QWebEnginePage (or QWebEngineView.page()) like QWebEnginePage.printToPdf(), but in that case I should use loadFinished signal for QWebEnginePage.load() and pdfPrintingFinished signal for QWebEnginePage.printToPdf(). Those signals will be connected to methods that won't run in QRunnable thread any more. They will run in main thread slowing the gui (those two methods can be slow, not to mention I want to open Adobe Reader with generated pdf document also in thread).
How to accomplish that all that code runs in thread (QRunnable or some other) and not to go back to main thread?
Similar question is here, but it seems it is pending without further discussion.