window.onload = function (){
new QWebChannel(qt.webChannelTransport, function (channel){
window.printer = channel.objects.printer;//此处channel.objects.printer中的printer就是上文提到的功能类注册的标识名
});};
用前端的单击事件来调用后端的函数:
function sendMes(){// 调用python端的功能类的方法执行操作
printer.testTxt("你收到一条网页发送的消息!")}
<!DOCTYPE html><head><meta charset="utf-8"/><title>QWebChannel测试</title><!--引入交互js--><script type="text/javascript" src="qwebchannel.js"></script><style type="text/css">
html {
height:100%;
width:100%;}#send {
width: 90px;
margin:0;}#output {
width:100%;
height: 500px;}</style><!--业务js--><script type="text/javascript">
window.onload = function (){
new QWebChannel(qt.webChannelTransport, function (channel){// 获取qt中绑定的交互对象
window.pyjs = channel.objects.interact_obj
// js 绑定qt中的信号
pyjs.sig_send_to_js.connect(function (str){
document.getElementById("output").value =str;});// 按钮点击事件
document.getElementById("send").onclick = function (){
var text_area = document.getElementById("output");if(!text_area.value){return;}// js调用qt中的方法
pyjs.receive_str_from_js(text_area.value)
text_area.value ="";}});}</script></head><body><textarea id="output">web控件内容!</textarea><inputtype="submit"id="send" value="同步到Qt" onclick="javascript:click();"/></body></html>
中间涉及到qwebchannel.js文件
/******************************************************************************** Copyright (C)2016 The Qt Company Ltd.** Contact: http://www.qt.io/licensing/**** This fileis part of the examples of the Qt Toolkit.**** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:**** "Redistribution and use in source and binary forms,withor without
** modification, are permitted provided that the following conditions are
** met:*** Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.*** Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in** the documentation and/or other materials provided with the
** distribution.*** Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
**from this software without specific prior written permission.****** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
**"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
**(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**** $QT_END_LICENSE$
******************************************************************************/"use strict";
var QWebChannelMessageTypes ={
signal:1,
propertyUpdate:2,
init:3,
idle:4,
debug:5,
invokeMethod:6,
connectToSignal:7,
disconnectFromSignal:8,
setProperty:9,
response:10,};
var QWebChannel = function(transport, initCallback){if(typeof transport !=="object"|| typeof transport.send !=="function"){
console.error("The QWebChannel expects a transport object with a send function and onmessage callback property."+" Given is: transport: "+ typeof(transport)+", transport.send: "+ typeof(transport.send));return;}
var channel = this;
this.transport = transport;
this.send = function(data){if(typeof(data)!=="string"){
data = JSON.stringify(data);}
channel.transport.send(data);}
this.transport.onmessage = function(message){
var data = message.data;if(typeof data ==="string"){
data = JSON.parse(data);}
switch (data.type){
case QWebChannelMessageTypes.signal:
channel.handleSignal(data);break;
case QWebChannelMessageTypes.response:
channel.handleResponse(data);break;
case QWebChannelMessageTypes.propertyUpdate:
channel.handlePropertyUpdate(data);break;
default:
console.error("invalid message received:", message.data);break;}}
this.execCallbacks ={};
this.execId =0;
this.exec= function(data, callback){if(!callback){//if no callback is given, send directly
channel.send(data);return;}if(channel.execId === Number.MAX_VALUE){// wrap
channel.execId = Number.MIN_VALUE;}if(data.hasOwnProperty("id")){
console.error("Cannot exec message with property id: "+ JSON.stringify(data));return;}
data.id= channel.execId++;
channel.execCallbacks[data.id]= callback;
channel.send(data);};
this.objects ={};
this.handleSignal = function(message){
var object= channel.objects[message.object];if(object){object.signalEmitted(message.signal, message.args);}else{
console.warn("Unhandled signal: "+ message.object+"::"+ message.signal);}}
this.handleResponse = function(message){if(!message.hasOwnProperty("id")){
console.error("Invalid response message received: ", JSON.stringify(message));return;}
channel.execCallbacks[message.id](message.data);
delete channel.execCallbacks[message.id];}
this.handlePropertyUpdate = function(message){for(var i in message.data){
var data = message.data[i];
var object= channel.objects[data.object];if(object){object.propertyUpdate(data.signals, data.properties);}else{
console.warn("Unhandled property update: "+ data.object+"::"+ data.signal);}}
channel.exec({type: QWebChannelMessageTypes.idle});}
this.debug = function(message){
channel.send({type: QWebChannelMessageTypes.debug, data: message});};
channel.exec({type: QWebChannelMessageTypes.init}, function(data){for(var objectName in data){
var object= new QObject(objectName, data[objectName], channel);}// now unwrap properties, which might reference other registered objects
for(var objectName in channel.objects){
channel.objects[objectName].unwrapProperties();}if(initCallback){
initCallback(channel);}
channel.exec({type: QWebChannelMessageTypes.idle});});};
function QObject(name, data, webChannel){
this.__id__ = name;
webChannel.objects[name]= this;// List of callbacks that get invoked upon signal emission
this.__objectSignals__ ={};// Cache of all properties, updated when a notify signal is emitted
this.__propertyCache__ ={};
var object= this;//----------------------------------------------------------------------
this.unwrapQObject = function(response){if(response instanceof Array){// support list of objects
var ret = new Array(response.length);for(var i =0; i < response.length;++i){
ret[i]=object.unwrapQObject(response[i]);}return ret;}if(!response
|| !response["__QObject*__"]|| response.id=== undefined){return response;}
var objectId = response.id;if(webChannel.objects[objectId])return webChannel.objects[objectId];if(!response.data){
console.error("Cannot unwrap unknown QObject "+ objectId +" without data.");return;}
var qObject = new QObject( objectId, response.data, webChannel );
qObject.destroyed.connect(function(){if(webChannel.objects[objectId]=== qObject){
delete webChannel.objects[objectId];// reset the now deleted QObject to an empty {}object// just assigning {} though would not have the desired effect, but the
// below also ensures all external references will see the empty map// NOTE: this detour is necessary to workaround QTBUG-40021
var propertyNames =[];for(var propertyName in qObject){
propertyNames.push(propertyName);}for(var idx in propertyNames){
delete qObject[propertyNames[idx]];}}});// here we are already initialized,and thus must directly unwrap the properties
qObject.unwrapProperties();return qObject;}
this.unwrapProperties = function(){for(var propertyIdx inobject.__propertyCache__){object.__propertyCache__[propertyIdx]=object.unwrapQObject(object.__propertyCache__[propertyIdx]);}}
function addSignal(signalData, isPropertyNotifySignal){
var signalName = signalData[0];
var signalIndex = signalData[1];object[signalName]={
connect: function(callback){if(typeof(callback)!=="function"){
console.error("Bad callback given to connect to signal "+ signalName);return;}object.__objectSignals__[signalIndex]=object.__objectSignals__[signalIndex]||[];object.__objectSignals__[signalIndex].push(callback);if(!isPropertyNotifySignal && signalName !=="destroyed"){// only required for"pure" signals, handled separately for properties in propertyUpdate
// also note that we always get notified about the destroyed signal
webChannel.exec({type: QWebChannelMessageTypes.connectToSignal,object:object.__id__,
signal: signalIndex
});}},
disconnect: function(callback){if(typeof(callback)!=="function"){
console.error("Bad callback given to disconnect from signal "+ signalName);return;}object.__objectSignals__[signalIndex]=object.__objectSignals__[signalIndex]||[];
var idx =object.__objectSignals__[signalIndex].indexOf(callback);if(idx ===-1){
console.error("Cannot find connection of signal "+ signalName +" to "+ callback.name);return;}object.__objectSignals__[signalIndex].splice(idx,1);if(!isPropertyNotifySignal &&object.__objectSignals__[signalIndex].length ===0){// only required for"pure" signals, handled separately for properties in propertyUpdate
webChannel.exec({type: QWebChannelMessageTypes.disconnectFromSignal,object:object.__id__,
signal: signalIndex
});}}};}/*** Invokes all callbacks for the given signalname. Also works forproperty notify callbacks.*/
function invokeSignalCallbacks(signalName, signalArgs){
var connections =object.__objectSignals__[signalName];if(connections){
connections.forEach(function(callback){
callback.apply(callback, signalArgs);});}}
this.propertyUpdate = function(signals, propertyMap){// update property cache
for(var propertyIndex in propertyMap){
var propertyValue = propertyMap[propertyIndex];object.__propertyCache__[propertyIndex]= propertyValue;}for(var signalName in signals){// Invoke all callbacks,as signalEmitted() does not. This ensures the
//property cache is updated before the callbacks are invoked.
invokeSignalCallbacks(signalName, signals[signalName]);}}
this.signalEmitted = function(signalName, signalArgs){
invokeSignalCallbacks(signalName, signalArgs);}
function addMethod(methodData){
var methodName = methodData[0];
var methodIdx = methodData[1];object[methodName]= function(){
var args =[];
var callback;for(var i =0; i < arguments.length;++i){if(typeof arguments[i]==="function")
callback = arguments[i];else
args.push(arguments[i]);}
webChannel.exec({"type": QWebChannelMessageTypes.invokeMethod,"object":object.__id__,"method": methodIdx,"args": args
}, function(response){if(response !== undefined){
var result =object.unwrapQObject(response);if(callback){(callback)(result);}}});};}
function bindGetterSetter(propertyInfo){
var propertyIndex = propertyInfo[0];
var propertyName = propertyInfo[1];
var notifySignalData = propertyInfo[2];// initialize property cache with current value
// NOTE:if this is an object, it isnot directly unwrapped as it might
// reference other QObject that we do not know yet
object.__propertyCache__[propertyIndex]= propertyInfo[3];if(notifySignalData){if(notifySignalData[0]===1){// signal name is optimized away, reconstruct the actual name
notifySignalData[0]= propertyName +"Changed";}
addSignal(notifySignalData, true);}
Object.defineProperty(object, propertyName,{
configurable: true,
get: function (){
var propertyValue =object.__propertyCache__[propertyIndex];if(propertyValue === undefined){// This shouldn't happen
console.warn("Undefined value in property cache for property \""+ propertyName +"\" in object "+object.__id__);}return propertyValue;},set: function(value){if(value === undefined){
console.warn("Property setter for "+ propertyName +" called with undefined value!");return;}object.__propertyCache__[propertyIndex]= value;
webChannel.exec({"type": QWebChannelMessageTypes.setProperty,"object":object.__id__,"property": propertyIndex,"value": value
});}});}//----------------------------------------------------------------------
data.methods.forEach(addMethod);
data.properties.forEach(bindGetterSetter);
data.signals.forEach(function(signal){ addSignal(signal, false);});for(var name in data.enums){object[name]= data.enums[name];}}//required for use with nodejs
if(typeof module ==='object'){
module.exports ={
QWebChannel: QWebChannel
};}