• 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 + "
    ";
                }
                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>

    结果如下:

     



  • 相关阅读:
    Python-装饰器进阶
    JavaScript-CasperJs使用教程
    Python-第三方库requests详解
    PHP-PHP程序员的技术成长规划(By黑夜路人)
    Bootstrap-学习系列
    CSS-常用媒体查询
    Git-随笔
    工具-各种开源
    PHP-PHP5.3及以上版本中检查json格式的方法
    VIM-技巧
  • 原文地址:https://www.cnblogs.com/wkcagd/p/7732330.html
Copyright © 2020-2023  润新知