PyQt 5使用QWebEngineView控件来展示HTML 页面,对老版本中的QWebView类不再进行维护,因为 QWebEngineView使用 Chromium内核可以给用户带来更好的体验。
Qt慢慢淘汰了古老的 WebKit,取而代之的是使用WebEngine框架。WebEngine是基于谷歌的 Chromium引擎开发的,也就是内部集成了谷歌的Chromium引擎。WebEngine框架是基于Chromium上的 Content API封装,投入成本比较小,可以很好地支持HTML 5。
在PyQt5中可以通过 PyQt5.QtWebKitWidgets.QWebEngineView类来使用网页控件
Qobject → QLayout → QWidget → QWenEngineView
方法 | 描述 |
---|---|
load(QUrl url) | 加载指定的URL并显示 |
setHtml(QString &html) | 将网页视图的内容设置为指定的HTML内容 |
OWebEngineView控件使用load()函数加载一个 Web页面,实际上就是使用HTTP GET方法加载 Web页面。这个控件既可以加载本地的Web页面也可以加载远程的外部 Web页面。
先要自行安装
pip install PyQtWebEngine -i https://pypi.tuna.tsinghua.edu.cn/simple
from PyQt5.QtCore import QUrl
from PyQt5.QtWebEngineWidgets import *
view = QWebEngineView()
view.load(QUrl("https://blog.csdn.net/weixin_44226181?type=blog"))
view.show()
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *
import sys
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("打开外部网页案例")
self.setGeometry(5,30,1355,730)
self.browser = QWebEngineView()
self.browser.load(QUrl("https://blog.csdn.net/weixin_44226181?type=blog"))
self.setCentralWidget(self.browser)
if __name__ == '__main__':
from pyqt5_plugins.examples.exampleqmlitem import QtCore
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *
import sys
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("打开本地页面案例")
self.setGeometry(5,30,555,330)
self.browser = QWebEngineView()
url = r'D:/DingJiaxiong/PycharmProjects/PyQt5Study/网页交互/index.html'
self.browser.load(QUrl(url))
self.setCentralWidget(self.browser)
if __name__ == '__main__':
from pyqt5_plugins.examples.exampleqmlitem import QtCore
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *
import sys
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("打开本地页面HTML代码案例")
self.setGeometry(5, 30, 555, 330)
self.browser = QWebEngineView()
self.browser.setHtml("""
丁家雄!
Hello,DingJiaxiong!
""")
self.setCentralWidget(self.browser)
if __name__ == '__main__':
from pyqt5_plugins.examples.exampleqmlitem import QtCore
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
经过测试,使用 QWebEngine View对象的setHtml())函数渲染HTML页面时,如果页面中使用的JavaScript代码超过2MB,程序渲染的页面就会渲染失败,页面中会出现大片的空白。
通过 QWebEnginePage类的 runJavaScript(str, Callable)函数可以很方便地实现PyQt和 HTML/JavaScript的双向通信,也实现了Python 代码和 HTML/JavaScript 代码的解耦,便于开发人员进行分工协作。
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton
from PyQt5.QtWebEngineWidgets import QWebEngineView
import sys
from pyqt5_plugins.examples.exampleqmlitem import QtCore
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
# 创建一个 application实例
app = QApplication(sys.argv)
win = QWidget()
win.setWindowTitle('Web页面中的JavaScript与 QWebEngineView交互例子')
# 创建一个垂直布局器
layout = QVBoxLayout()
win.setLayout(layout)
# 创建一个 QWebEngineView 对象
view = QWebEngineView()
view.setHtml('''
A Demo Page
''')
# 创建一个按钮去调用 JavaScript代码
button = QPushButton('设置全名')
def js_callback(result):
print(result)
def complete_name():
view.page().runJavaScript('completeAndReturnName();', js_callback)
# 按钮连接 'complete_name'槽,当点击按钮是会触发信号
button.clicked.connect(complete_name)
# 把QWebView和button加载到layout布局中
layout.addWidget(view)
layout.addWidget(button)
# 显示窗口和运行app
win.show()
sys.exit(app.exec_())
JavaScript调用PyOt代码,是指PyOt可以与加载的 Web页面进行双向的数据交互。首先,使用QWebEngineView对象加载Web页面后,就可以获得页面中表单输入数据,在Web页面中通过JavaScript 代码收集用户提交的数据。然后,在 Web页面中,JavaScript通过桥连接方式传递数据给PyQt。最后,PyQt 接收到页面传递的数据,经过业务处理后,还可以把处理过的数据返给Web页面。
创建QWebChannel对象
创建QWebChannel对象,注册一个需要桥接的对象,以便Web页面的JavaScript使用。
channel = QWebChannel()
myobj = MySharedObject()
channel.registerObject("bridge",myobj)
view.page().setWebChannel(channel)
创建共享数据的PyQt对象
class MySharcedObject(QWidget):
def __init__(self):
super(MySharcedObject, self).__init__()
def _setStrValue(self,str):
print("获得页面参数: %s" % str)
# 定义对外发布的方法
strValue = pyqtProperty(str,fset = _setStrValue)
对外提供的 PyOt对象方法,需要使用pyqtProperty()函数让它暴露出来。
在PyQt5中使用pyqtProperty()函数来定义PyQt对象中的属性,这个函数的使用方式与标准Python模块中的property()函数相同。PyQt5.QtCore.pyqtProperty()函数的API如下:
PyQt5.Qtcore.pyqtProperty(type[, fget=None[,fset=None[, freset=None [,fdel=None[, doc=None[, designable=True[, scriptable=True[, stored=True[,user=False[,constant=False[, final=False[,notify=None [,
revision=0]]]]]]]]])
参数说明
参数 | 说明 |
---|---|
type | 必填,属性的类型 |
fget | 可选,用于获取属性的值 |
fset | 可选,用于设置属性的值 |
freset | 可选,用于将属性的值重置为它的默认值 |
fdel | 可选,用于删除属性 |
Doc | 可选,属性的文档字符串 |
designable | 可选,设置Qt DESIGNABLE标志 |
scriptable | 可选,设置Qt SCRIPTABLE标志 |
stored | 可选,设置Qt STORED标志 |
user | 可选,设置Qt USER标志 |
constant | 可选,设置Qt CONSTANT标志 |
final | 可选,设置Qt FINAL标志 |
notify | 可选,未绑定的通知信号 |
revision | 可选,将版本导出到QML |
测试案例
from PyQt5.QtCore import QObject, pyqtProperty
class MyObject(QObject):
def __init__(self, inVal=20):
self.val = inVal
def readVal(self):
print('readVal=%s' % self.val)
return self.val
def setVal(self, val):
print('setVal=%s' % val)
self.val = val
ppVal = pyqtProperty(int, readVal, setVal)
if __name__ == '__main__':
obj = MyObject()
print('\n#1')
obj.ppVal = 10
print('\n#2')
print('obj.ppVal=%s' % obj.ppVal)
print('obj.readVal()=%s' % obj.readVal())
创建调用PyQt的Web页面
本机直接启动服务
DOCTYPE html>
<html lang="en">
<head>
<title>A Demo Pagetitle>
<meta charset="UTF-8">
<script src="qwebchannel.js">script>
<script>
function completeAndReturnName() {
var fname = document.getElementById('fname').value;
var lname = document.getElementById('lname').value;
var full = lname + ' ' + fname;
document.getElementById('fullname').value = full;
document.getElementById('submit-btn').style.display = 'block';
return full;
}
document.addEventListener("DOMContentLoaded", function () {
new QWebChannel(qt.webChannelTransport, function (channel) {
//alert('111 channel=' + channel )
window.bridge = channel.objects.bridge;
alert('bridge=' + bridge + '\n从pyqt传来的参数=' + window.bridge.strValue);
});
});
function onShowMsgBox() {
//alert('window.bridge=' + window.bridge);
if (window.bridge) {
//alert('bridge.strValue=' + window.bridge.strValue ) ;
//bridge.sayHello('999')
var fname = document.getElementById('fname').value;
window.bridge.strValue = fname;
}
}
script>
head>
<body>
<form>
<label for="姓名">user name:label>
<input type="text" name="fname" id="fname">input>
<br/>
<input type="button" value="传递参数到pyqt" onclick="onShowMsgBox()">
<input type="reset" value='重置'/>
form>
body>
html>
实例
from PyQt5.QtWidgets import QApplication , QWidget , QVBoxLayout
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import QUrl
from MySharedObject import MySharedObject
from PyQt5.QtWebChannel import QWebChannel
import sys
from pyqt5_plugins.examples.exampleqmlitem import QtCore
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
# 创建一个 application实例
app = QApplication(sys.argv)
win = QWidget()
win.setWindowTitle('Web页面中的JavaScript与 QWebEngineView交互例子')
# 创建一个垂直布局器
layout = QVBoxLayout()
win.setLayout(layout)
# 创建一个 QWebEngineView 对象
view = QWebEngineView()
htmlUrl = 'http://127.0.0.1:8000/web/index.html'
view.load( QUrl( htmlUrl ))
# 创建一个 QWebChannel对象,用来传递pyqt参数到JavaScript
channel = QWebChannel( )
myObj = MySharedObject()
channel.registerObject( "bridge", myObj )
view.page().setWebChannel(channel)
# 把QWebView和button加载到layout布局中
layout.addWidget(view)
# 显示窗口和运行app
win.show()
sys.exit(app.exec_())
MySharedObject.py
from PyQt5.QtCore import QObject
from PyQt5.QtCore import pyqtProperty
from PyQt5.QtWidgets import QWidget,QMessageBox
class MySharedObject(QWidget):
def __init__( self):
super( MySharedObject, self).__init__()
def _getStrValue( self):
#
return '100'
def _setStrValue( self, str ):
#
print('获得页面参数 :%s'% str )
QMessageBox.information(self,"Information", '获得页面参数 :%s'% str )
#需要定义对外发布的方法
strValue = pyqtProperty(str, fget=_getStrValue, fset=_setStrValue)