为什么在使用QWebView时,必须在QNetworkRequest完成前调用QApplication.processEvents()?
通常情况下,当我通过 Qt 4.8 进行网络请求时,我不需要特别调用 QApplication.processEvents()
方法(可以参考这个 StackOverflow 的代码示例)。
但是,当我在 QWebView
中通过 JavaScript 发起网络请求时,如果不一直调用这个方法直到请求完成,它就不会正常工作,下面的例子就说明了这一点(这里有个语法高亮的示例)。
说明:
如果我不调用 processEvents()
方法,网络请求根本不会发送,尽管我理解的情况是 finished
的槽函数似乎已经连接好了。
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_())
1 个回答
3
你在使用QNetworkAccessManager时,有一个很大的区别和链接中提到的例子。注意到你使用的是同步方式:在'request'这个槽函数中,你通过等待回复来阻塞事件循环,这样QNetworkAccessManager就无法正常工作,除非你手动推送事件。而链接中的例子是异步的:它创建请求,连接'finished'信号,并让事件循环继续工作。这样事件循环就不会被阻塞,网络管理器就能正常运作。我理解在你的情况下,'request'槽函数需要是同步的,所以这里必须使用processEvents。
编辑
如果你想让request
变成异步的,那么你需要确保QNetworkAccessManager
对象在request
方法之外是持久的。你可以在__init__(self)
中初始化它,并用它来进行POST请求。可能QNetworkReply
也需要持久化,你需要检查一下。