Why must QApplication.processEvents() be called until QNetworkRequest is finished when using QWebView?

StackOverflow https://stackoverflow.com/questions/23345290

Pregunta

Normally, when I perform a network request via Qt 4.8 I don't need to explicitly run QApplication.processEvents() (see this StackOverflow code example).

However when I issue the network request from JavaScript in a QWebView, this will not work unless I call that method until the request is finished, as seen below (syntax-highlighted gist here).

CLARIFICATION:
The request is not even sent when I omit the processEvents() call although the finished slots seem to be attached as I understand it.

from PyQt4 import QtCore, QtGui, QtNetwork, QtWebKit

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        QtNetwork.QNetworkProxyFactory.setUseSystemConfiguration(True)
        self.view = QtWebKit.QWebView(self)
        self.setCentralWidget(self.view)
        self.view.setPage(QtWebKit.QWebPage(self.view))

        self.view.page().mainFrame().javaScriptWindowObjectCleared.connect(self.refreshJS)

        self.view.setHtml(
            '''<html>
            <body>
                    LOADING...
                    <script>
                    <!--
                            APP.request();
                    //-->
                    </script>
            </body>
            </html>'''
        )

    @QtCore.pyqtSlot()
    def request(self):
        request = QtNetwork.QNetworkRequest(QtCore.QUrl('http://localhost/test.php'))

        manager = QtNetwork.QNetworkAccessManager()
        manager.finished.connect(self.managerFinished)

        reply = manager.post(request, b'a=A')
        reply.finished.connect(self.finished)

        ############################################################
        ### FIXME: Request never even *sent* if this is missing  ###
        ############################################################

        while not reply.isFinished():
          QtGui.QApplication.processEvents()

        ##########################################################

        print('request FINISHED? '+str(reply.isFinished())+', ERROR '+str(reply.error()))

    def finished(self):
        print('finished')

    def managerFinished(self):
        print('managerFinished')

    def refreshJS(self):
        print('refreshJS')
        self.view.page().mainFrame().addToJavaScriptWindowObject('APP', self)

if __name__ == '__main__':
    import os, sys
    app = QtGui.QApplication(sys.argv)
    MainWindow().show()
    sys.exit(app.exec_())
¿Fue útil?

Solución

There is one big difference between your usage of QNetworkAccessManager and one pointed in the link. Notice that your version is synchronous: you block the event loop in 'request' slot by waiting for reply, thus QNetworkAccessManager cannot work unless you push the events by hand. From the other side the pointed example is asynchronous: it creates request, connects 'finished' signal and lets event loop to work. This way event loop is not blocked and network manager works well. I understand that in your situation 'request' slot needs to be synchronous, thus processEvents is a must here.

EDIT

If you want to make the request asynchronous, then you need to be sure that QNetworkAccessManager object is persistent outside the request method. Initialize it in __init__(self) and use it to POST in the request. ProbablyQNetworkReply` needs to be persistent too, you need to check it.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top