Графический интерфейс заблокирован при вызове QWebView.print_()
Я работаю с Python 2.7 и PySide, и мне нужно экспортировать большой HTML-файл в PDF-файл.
Я пытался загрузить его с QWebView
а затем распечатать его в QPrinter
настроен для pdf-формата. это отлично работает
Однако с моим решением есть одна большая проблема: когда я звоню QWebView.print_()
, графический интерфейс заблокирован, и для окон, похоже, моя программа потерпела крах. Это происходит из-за большого размера моего HTML (1000 страниц и более).
Итак, мой вопрос: есть ли чистый способ избежать этого "крушения"?
РЕДАКТИРОВАТЬ:
Я попытался сделать печать в отдельном потоке, как предложил jadkik94. Насколько я понимаю, код ниже должен работать. К сожалению, это происходит случайным образом.;) Есть идеи, почему это так?
import sys
from PySide import QtGui, QtWebKit, QtCore
class PrintThread(QtCore.QThread):
def __init__(self, webview, printer, parent=None):
super(PrintThread, self).__init__(parent)
self._webview = webview
self._printer = printer
def run(self):
self._webview.print_(self._printer)
class MyWindow(QtGui.QMainWindow):
def __init__(self):
super(MyWindow,self).__init__()
# a printer to print on
self._myPrinter = QtGui.QPrinter()
self._myPrinter.setOutputFormat(QtGui.QPrinter.PdfFormat)
self._myPrinter.setPrintRange(QtGui.QPrinter.AllPages)
self._myPrinter.setOrientation(QtGui.QPrinter.Portrait)
self._myPrinter.setPaperSize(QtGui.QPrinter.A4)
self._myPrinter.setNumCopies(1)
# a webview for loading the html and printing it
self._webview = QtWebKit.QWebView(self)
self.setCentralWidget( self._webview )
self._webview.loadFinished.connect(self.webViewLoadFinished)
# print-preview-dialog
self._previewDlg = QtGui.QPrintPreviewDialog(self._myPrinter)
#self._previewDlg.paintRequested.connect(self.dlgPaintRequestNoThread) # works but freezes the mainthread
self._previewDlg.paintRequested.connect(self.dlgPaintRequestWithThread) # as far is i understand this should work... but crashes randomly ;)
# load the html
self._webview.load('index.htm') # file is 2MB
def webViewLoadFinished(self):
# when webview has finished loading, show the dialog
self._previewDlg.show()
def dlgPaintRequestNoThread(self):
self._webview.print_(self._myPrinter)
def dlgPaintRequestWithThread(self):
self.printPages()
# wait for the print-thread to finish without blocking the mainthread
eventLoop = QtCore.QEventLoop()
self.worker.finished.connect(eventLoop.quit)
eventLoop.exec_()
def printPages(self):
self.worker = PrintThread(self._webview, self._myPrinter)
self.worker.finished.connect(self.donePrinting)
self.progressDlg = QtGui.QProgressDialog()
self.progressDlg.setCancelButton(None)
self.progressDlg.show()
self.worker.start()
def donePrinting(self):
self.progressDlg.close()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = MyWindow()
window.show()
app.exec_()
1 ответ
Я считаю, что вам нужно использовать темы, чтобы решить эту проблему. Похоже, что QWebView.print_()
запускается в основном потоке и, таким образом, блокирует запуск вашего графического интерфейса.
У вас есть 2 варианта, вы либо используете Python threading
модуль или Qt's QThread
s.
Этот вопрос показывает, как вы можете использовать QThread
s. В принципе:
class PrintThread(QtCore.QThread):
def __init__(self, webview, parent=None):
super(PrintThread, self).__init__(parent)
self.webview = webview
def run(self):
# Get a printer from somewhere
self.webview.print_(printer)
А потом:
def printPage(self):
worker = PrintThread(self.page)
worker.finished.connect(self.donePrinting)
# Show a loading dialog
worker.start()
def donePrinting(self):
# Close the loading dialog
pass
Вы можете применить то же самое с модулем потоков, но так как вы уже используете pyside, почему бы не использовать его и для этого. Кроме того, я не уверен, что другой поток (кроме QThread) может связываться с Qt GUI, он может просто сказать вам, что вы не можете получить доступ к потоку GUI из другого потока (хотя и не уверен).