如何使用QWebChannel从python接收数据到js?
How to receive data from python to js using QWebChannel?
我试图让我的 PyQt 应用程序与 JS 通信,但无法从 python 获取值。我在 python 一侧有两个插槽用于获取和打印数据。在这个例子中,一个int从JS传递给python,python将它加5并传递回来,然后JS调用另一个槽打印新值。
var backend = null;
var x = 15;
new QWebChannel(qt.webChannelTransport, function (channel) {
backend = channel.objects.backend;
backend.getRef(x, function(pyval){
backend.printRef(pyval)
});
});
@pyqtSlot(int)
def getRef(self, x):
print('inside getRef', x)
return x + 5
@pyqtSlot(int)
def printRef(self, ref):
print('inside printRef', ref)
输出:
inside getRef 15
Could not convert argument QJsonValue(null) to target type int .
预计:
inside getRef 15
inside printRef 20
我不明白为什么返回值为空。我如何将该 pyval 存储到 js 端的变量中以备后用?
在 C++ 中,一个方法可以 return 一个值,它必须被声明为 Q_INVOKABLE
,在 PyQt 中等效的是在 @pyqtSlot
装饰器中使用 result
:
├── index.html
└── main.py
main.py
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets, QtWebChannel
class Backend(QtCore.QObject):
@QtCore.pyqtSlot(int, <b>result=int</b>)
def getRef(self, x):
print("inside getRef", x)
return x + 5
@QtCore.pyqtSlot(int)
def printRef(self, ref):
print("inside printRef", ref)
if __name__ == "__main__":
import os
import sys
app = QtWidgets.QApplication(sys.argv)
backend = Backend()
view = QtWebEngineWidgets.QWebEngineView()
channel = QtWebChannel.QWebChannel()
view.page().setWebChannel(channel)
channel.registerObject("backend", backend)
current_dir = os.path.dirname(os.path.realpath(__file__))
filename = os.path.join(current_dir, "index.html")
url = QtCore.QUrl.fromLocalFile(filename)
view.load(url)
view.resize(640, 480)
view.show()
sys.exit(app.exec_())
index.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script type="text/javascript">
var backend = null;
var x = 5;
window.onload = function()
{
new QWebChannel(qt.webChannelTransport, function(channel) {
backend = channel.objects.backend;
backend.getRef(x, function(pyval) {
backend.printRef(pyval);
});
});
}
</script>
</head>
</html>
更新:
一般来说,QtWebChannel只能从Qt端传输可以转换成QJsonObject的信息,从javascript端传输可以转换成JSON的数据。
所以有特殊情况:
- int
- 浮动
- str
- list:是否支持发送和接收列表,但可以是数字、字符串等元素,也可以是支持前面基本类型的字典等列表。
class Backend(QtCore.QObject):
@QtCore.pyqtSlot(result=list)
def return_list(self):
return [0.0, 1.5, 'Hello', ['Stack', 5.0], {'a': {'b': 'c'}}]
@QtCore.pyqtSlot(list)
def print_list(self, l):
print(l)
backend = channel.objects.backend;
backend.return_list(function(pyval) {
backend.print_list(pyval);
});
输出:
[0.0, 1.5, 'Hello', ['Stack', 5.0], {'a': {'b': 'c'}}]
- dict:
class Backend(QtCore.QObject):
@QtCore.pyqtSlot(result="QJsonObject")
def return_dict(self):
return {"a": 1.5, "b": {"c": 2}, "d": [1, "3", "4"]}
@QtCore.pyqtSlot("QJsonObject")
def print_dict(self, ref):
print(ref)
backend = channel.objects.backend;
backend.return_dict(function(pyval) {
backend.print_dict(pyval);
});
输出:
{'a': <PyQt5.QtCore.QJsonValue object at 0x7f3841d50150>, 'b': <PyQt5.QtCore.QJsonValue object at 0x7f3841d501d0>, 'd': <PyQt5.QtCore.QJsonValue object at 0x7f3841d50250>}
如您所见,QJsonValue 是 returned 的,因此获取信息可能很繁琐,因此解决方法是将它们打包在一个列表中:
class Backend(QtCore.QObject):
@QtCore.pyqtSlot(result=list)
def return_list(self):
d = {"a": 1.5, "b": {"c": 2}, "d": [1, "3", "4"]}
return [d]
@QtCore.pyqtSlot(list)
def print_list(self, ref):
d, *_ = ref
print(d)
backend = channel.objects.backend;
backend.return_list(function(pyval) {
backend.print_list(pyval);
});
输出:
{'a': 1.5, 'b': {'c': 2.0}, 'd': [1.0, '3', '4']}
更新2:
一种通用的传递信息的方式是使用JSON,即将python或js对象转换成字符串使用json.dumps()
和JSON.stringify()
,分别发送;当在 python 或 js 中接收时,必须分别使用 json.loads()
和 JSON.parse()
转换字符串:
class Backend(QtCore.QObject):
@QtCore.pyqtSlot(str, result=str)
def getRef(self, o):
print("inside getRef", o)
py_obj = json.loads(o)
py_obj["c"] = ("Hello", "from", "Python")
return json.dumps(py_obj)
@QtCore.pyqtSlot(str)
def printRef(self, o):
py_obj = json.loads(o)
print("inside printRef", py_obj)
var backend = null;
window.onload = function()
{
new QWebChannel(qt.webChannelTransport, function(channel) {
backend = channel.objects.backend;
var x = {a: "1000", b: ["Hello", "From", "JS"]}
backend.getRef(JSON.stringify(x), function(y) {
js_obj = JSON.parse(y);
js_obj["f"] = false;
backend.printRef(JSON.stringify(js_obj));
});
});
}
inside getRef {"a":"1000","b":["Hello","From","JS"]}
inside printRef {'a': '1000', 'b': ['Hello', 'From', 'JS'], 'c': ['Hello', 'from', 'Python'], 'f': False}
我试图让我的 PyQt 应用程序与 JS 通信,但无法从 python 获取值。我在 python 一侧有两个插槽用于获取和打印数据。在这个例子中,一个int从JS传递给python,python将它加5并传递回来,然后JS调用另一个槽打印新值。
var backend = null;
var x = 15;
new QWebChannel(qt.webChannelTransport, function (channel) {
backend = channel.objects.backend;
backend.getRef(x, function(pyval){
backend.printRef(pyval)
});
});
@pyqtSlot(int)
def getRef(self, x):
print('inside getRef', x)
return x + 5
@pyqtSlot(int)
def printRef(self, ref):
print('inside printRef', ref)
输出:
inside getRef 15
Could not convert argument QJsonValue(null) to target type int .
预计:
inside getRef 15
inside printRef 20
我不明白为什么返回值为空。我如何将该 pyval 存储到 js 端的变量中以备后用?
在 C++ 中,一个方法可以 return 一个值,它必须被声明为 Q_INVOKABLE
,在 PyQt 中等效的是在 @pyqtSlot
装饰器中使用 result
:
├── index.html
└── main.py
main.py
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets, QtWebChannel
class Backend(QtCore.QObject):
@QtCore.pyqtSlot(int, <b>result=int</b>)
def getRef(self, x):
print("inside getRef", x)
return x + 5
@QtCore.pyqtSlot(int)
def printRef(self, ref):
print("inside printRef", ref)
if __name__ == "__main__":
import os
import sys
app = QtWidgets.QApplication(sys.argv)
backend = Backend()
view = QtWebEngineWidgets.QWebEngineView()
channel = QtWebChannel.QWebChannel()
view.page().setWebChannel(channel)
channel.registerObject("backend", backend)
current_dir = os.path.dirname(os.path.realpath(__file__))
filename = os.path.join(current_dir, "index.html")
url = QtCore.QUrl.fromLocalFile(filename)
view.load(url)
view.resize(640, 480)
view.show()
sys.exit(app.exec_())
index.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script type="text/javascript">
var backend = null;
var x = 5;
window.onload = function()
{
new QWebChannel(qt.webChannelTransport, function(channel) {
backend = channel.objects.backend;
backend.getRef(x, function(pyval) {
backend.printRef(pyval);
});
});
}
</script>
</head>
</html>
更新:
一般来说,QtWebChannel只能从Qt端传输可以转换成QJsonObject的信息,从javascript端传输可以转换成JSON的数据。
所以有特殊情况:
- int
- 浮动
- str
- list:是否支持发送和接收列表,但可以是数字、字符串等元素,也可以是支持前面基本类型的字典等列表。
class Backend(QtCore.QObject):
@QtCore.pyqtSlot(result=list)
def return_list(self):
return [0.0, 1.5, 'Hello', ['Stack', 5.0], {'a': {'b': 'c'}}]
@QtCore.pyqtSlot(list)
def print_list(self, l):
print(l)
backend = channel.objects.backend;
backend.return_list(function(pyval) {
backend.print_list(pyval);
});
输出:
[0.0, 1.5, 'Hello', ['Stack', 5.0], {'a': {'b': 'c'}}]
- dict:
class Backend(QtCore.QObject):
@QtCore.pyqtSlot(result="QJsonObject")
def return_dict(self):
return {"a": 1.5, "b": {"c": 2}, "d": [1, "3", "4"]}
@QtCore.pyqtSlot("QJsonObject")
def print_dict(self, ref):
print(ref)
backend = channel.objects.backend;
backend.return_dict(function(pyval) {
backend.print_dict(pyval);
});
输出:
{'a': <PyQt5.QtCore.QJsonValue object at 0x7f3841d50150>, 'b': <PyQt5.QtCore.QJsonValue object at 0x7f3841d501d0>, 'd': <PyQt5.QtCore.QJsonValue object at 0x7f3841d50250>}
如您所见,QJsonValue 是 returned 的,因此获取信息可能很繁琐,因此解决方法是将它们打包在一个列表中:
class Backend(QtCore.QObject):
@QtCore.pyqtSlot(result=list)
def return_list(self):
d = {"a": 1.5, "b": {"c": 2}, "d": [1, "3", "4"]}
return [d]
@QtCore.pyqtSlot(list)
def print_list(self, ref):
d, *_ = ref
print(d)
backend = channel.objects.backend;
backend.return_list(function(pyval) {
backend.print_list(pyval);
});
输出:
{'a': 1.5, 'b': {'c': 2.0}, 'd': [1.0, '3', '4']}
更新2:
一种通用的传递信息的方式是使用JSON,即将python或js对象转换成字符串使用json.dumps()
和JSON.stringify()
,分别发送;当在 python 或 js 中接收时,必须分别使用 json.loads()
和 JSON.parse()
转换字符串:
class Backend(QtCore.QObject):
@QtCore.pyqtSlot(str, result=str)
def getRef(self, o):
print("inside getRef", o)
py_obj = json.loads(o)
py_obj["c"] = ("Hello", "from", "Python")
return json.dumps(py_obj)
@QtCore.pyqtSlot(str)
def printRef(self, o):
py_obj = json.loads(o)
print("inside printRef", py_obj)
var backend = null;
window.onload = function()
{
new QWebChannel(qt.webChannelTransport, function(channel) {
backend = channel.objects.backend;
var x = {a: "1000", b: ["Hello", "From", "JS"]}
backend.getRef(JSON.stringify(x), function(y) {
js_obj = JSON.parse(y);
js_obj["f"] = false;
backend.printRef(JSON.stringify(js_obj));
});
});
}
inside getRef {"a":"1000","b":["Hello","From","JS"]}
inside printRef {'a': '1000', 'b': ['Hello', 'From', 'JS'], 'c': ['Hello', 'from', 'Python'], 'f': False}