QT:用QWebSocket实现webchannel,实现C++与HTML通信
基本原理是通过channel将C++对象暴露给HTML,在HTML中调用qwebchannel.js。前提是建立transport,QT只提供了一个抽象基类QWebChannelAbstractTransport,需要自己进行实现,官方建议用QWebSocket实现,并给出了实例。
1、实现Transport类,内置一个WebSocket套接字;
2、实现新的channel类,内置一个WebSocketServer;
3、利用新的channel注册C++对象,从而HTML可以使用该对象;
4、通过以下三种方式进行C++与HTML的交互:
4.1 在HTML中l连接C++ signal与js函数的
object.signal.connect(function(){});
4.2 在HTML中调用C++ public slots函数;
4.3 在HTML中调用C++ Q_INVOKABLE修饰的函数;
下面给出实例代码
5.1 WebSocketTransport类
websockettransport.h
1 #ifndef WEBSOCKETTRANSPORT_H 2 #define WEBSOCKETTRANSPORT_H 3 4 #include <QWebChannelAbstractTransport> 5 6 QT_BEGIN_NAMESPACE 7 class QWebSocket; 8 QT_END_NAMESPACE 9 10 class WebSocketTransport : public QWebChannelAbstractTransport 11 { 12 Q_OBJECT 13 public: 14 explicit WebSocketTransport(QWebSocket *socket); 15 virtual ~WebSocketTransport(); 16 17 void sendMessage(const QJsonObject &message) override; 18 19 private slots: 20 void textMessageReceived(const QString &message); 21 22 private: 23 QWebSocket *m_socket; 24 }; 25 26 #endif // WEBSOCKETTRANSPORT_H
websockettransport.cpp
1 #include "websockettransport.h" 2 3 #include <QDebug> 4 #include <QJsonDocument> 5 #include <QJsonObject> 6 #include <QWebSocket> 7 8 9 /*! 10 Construct the transport object and wrap the given socket. 11 12 The socket is also set as the parent of the transport object. 13 */ 14 WebSocketTransport::WebSocketTransport(QWebSocket *socket) 15 : QWebChannelAbstractTransport(socket) 16 , m_socket(socket) 17 { 18 connect(socket, &QWebSocket::textMessageReceived, 19 this, &WebSocketTransport::textMessageReceived); 20 connect(socket, &QWebSocket::disconnected, 21 this, &WebSocketTransport::deleteLater); 22 } 23 24 /*! 25 Destroys the WebSocketTransport. 26 */ 27 WebSocketTransport::~WebSocketTransport() 28 { 29 m_socket->deleteLater(); 30 } 31 32 /*! 33 Serialize the JSON message and send it as a text message via the WebSocket to the client. 34 */ 35 void WebSocketTransport::sendMessage(const QJsonObject &message) 36 { 37 QJsonDocument doc(message); 38 m_socket->sendTextMessage(QString::fromUtf8(doc.toJson(QJsonDocument::Compact))); 39 } 40 41 /*! 42 Deserialize the stringified JSON messageData and emit messageReceived. 43 */ 44 void WebSocketTransport::textMessageReceived(const QString &messageData) 45 { 46 QJsonParseError error; 47 QJsonDocument message = QJsonDocument::fromJson(messageData.toUtf8(), &error); 48 if (error.error) { 49 qWarning() << "Failed to parse text message as JSON object:" << messageData 50 << "Error is:" << error.errorString(); 51 return; 52 } else if (!message.isObject()) { 53 qWarning() << "Received JSON message that is not an object: " << messageData; 54 return; 55 } 56 emit messageReceived(message.object(), this); 57 }
5.2 WebSocketChannel类
websocketchannel.h
#ifndef WEBSOCKETCHANNEL_H #define WEBSOCKETCHANNEL_H #include <QWebChannel> class QWebSocketServer; class WebSocketTransport; //继承QWebchannel类,在内部建立socket server与transport中socket的连接 class WebSocketChannel : public QWebChannel { Q_OBJECT public: WebSocketChannel(QWebSocketServer *server); signals: void clientConnected(WebSocketTransport *client); private slots: void handleNewConnection(); private: QWebSocketServer *_server; }; #endif // WEBSOCKETCHANNEL_H
websocketchannel.cpp
#include "websocketchannel.h" #include <QWebSocketServer> #include "websockettransport.h" WebSocketChannel::WebSocketChannel(QWebSocketServer *server) :_server(server) { connect(server, &QWebSocketServer::newConnection, this, &WebSocketChannel::handleNewConnection); connect(this, &WebSocketChannel::clientConnected, this, &WebSocketChannel::connectTo);//connectTo槽继承自QWebchannel } void WebSocketChannel::handleNewConnection() { emit clientConnected(new WebSocketTransport(_server->nextPendingConnection())); }
main.cpp
#include <QApplication> #include <QDesktopServices> #include <QDialog> #include <QDir> #include <QFileInfo> #include <QUrl> #include <QWebChannel> #include <QWebSocketServer> int main(int argc, char** argv) { QApplication app(argc, argv); //建立QWebSocketServer,url是ws://localhost:12345 QWebSocketServer server(QStringLiteral("QWebChannel Standalone Example Server"), QWebSocketServer::NonSecureMode); if (!server.listen(QHostAddress::LocalHost, 12345)) { qFatal("Failed to open web socket server."); return 1; } //建立websocketchannl,该channel就可以用来通信了 WebSocketChannel channel(&server); // setup the UI Dialog dialog; // setup the core and publish it to the QWebChannel Core core(&dialog); //注册C++对象,该类要继承自QObject channel.registerObject(QStringLiteral("core"), &core); // open a browser window with the client HTML page QUrl url = QUrl::fromLocalFile(BUILD_DIR "/index.html"); QDesktopServices::openUrl(url); dialog.displayMessage(Dialog::tr("Initialization complete, opening browser at %1.").arg(url.toDisplayString())); dialog.show(); return app.exec(); }
index.html
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> //使用qwebchannel.js <script type="text/javascript" src="./qwebchannel.js"></script> <script type="text/javascript"> //BEGIN SETUP function output(message) { var output = document.getElementById("output"); output.innerHTML = output.innerHTML + message + "\n"; } window.onload = function() { var baseUrl = "ws://localhost:12345"; output("Connecting to WebSocket server at " + baseUrl + "."); var socket = new WebSocket(baseUrl); socket.onclose = function() { console.error("web channel closed"); }; socket.onerror = function(error) { console.error("web channel error: " + error); }; socket.onopen = function() { output("WebSocket connected, setting up QWebChannel."); new QWebChannel(socket, function(channel) { // make core object accessible globally window.core = channel.objects.core; document.getElementById("send").onclick = function() { var input = document.getElementById("input"); var text = input.value; if (!text) { return; } output("Sent message: " + text); input.value = ""; //调用C++公有槽函数 core.receiveText(text); core.hello(text); } //连接C++信号与javascript函数 core.sendText.connect(function(message) { output("Received message: " + message); }); core.receiveText("Client connected, ready to send/receive messages!"); output("Connected to WebChannel, ready to send/receive messages!"); }); } } //END SETUP </script> <style type="text/css"> html { height: 100%; width: 100%; } #input { width: 400px; margin: 0 10px 0 0; } #send { width: 90px; margin: 0; } #output { width: 500px; height: 300px; } </style> </head> <body> <textarea id="output"></textarea><br /> <input id="input" /><input type="submit" id="send" value="Send" onclick="javascript:click();" /> </body> </html>
结果如下:
版权声明:本文为wkcagd原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。