gui locked when calling QWebView.print_()
Question: I'm working with **Python 2.7** and **PySide** , and i need to export a big
html-file to a pdf-file.

I have tried loading it with a `QWebView` and then printing it to a `QPrinter`
configured for pdf-format. this works fine.

However, there is one big problem with my solution: when I call
`QWebView.print_()`, the gui is locked up, and for windows it looks like my
program has crashed. This happens because of the big size of my html (1000
pages and more).

So my question is: is there a clean way to avoid this 'crash' ?

EDIT:

I tried to do the printing in a separate thread, like jadkik94 suggested. As
far as I understand the code below should work. Unfortunately it crashes
randomly. ;) Any ideas why this is the case?

    
    
    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_()
    


Answer: I believe you need to use threads to solve this problem. It appears that
`QWebView.print_()` runs in the main thread, and thus blocks your GUI from
running.

You have 2 options, you either use Python's `threading` module or Qt's
`QThread`s.

[This question](http://stackoverflow.com/questions/10044197/how-to-get-
qthreads-to-work-in-a-console-pyside-program) shows how you can use
`QThread`s. Basically:

    
    
    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)
    

And then:

    
    
    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
    

You could apply the same thing with the threading module, but since you are
already using pyside, why not use it for that too. Also, I am not sure if
another thread (other than QThread) can mess with the Qt GUI, it might just
tell you you cannot access the GUI thread from another thread (not sure
though).

