Qt5.11 利用QWebChannel实现C++与JS的交互

网上有一篇与此类似的文章,而且网上大部分的文章基本上都是复制来复制去的,目前我看过的也就是俩DEMO了,而且都是缺斤少两的货(代码不全,复制过来也跑不起来)。。。

为此我专门自己花了几天(实则加起来也就几个小时)自己硬啃DEMO + 个人理解总算是把完整的DEMO给整出来了。

网上的DEMO这里引用一下:http://www.cnblogs.com/wkcagd/p/7732330.html

跟评论里说的一样,缺俩类的实现,尤其是Core类不知道是个什么鬼,而且我在Qt上无意中还发现了,原来这是官方的DEMO照搬了过来,搞的我好一阵折腾啊,半天没理解是个啥意思,毕竟第一次接触C++与JS的交互编程,要是用JS与PHP那就简单了,一个Ajax就搞定,不过这就扯远了。。。

这里我先把评论里的问题解决一下,评论里的问题也是我的问题。

首先qwebchannel.js文件是在Qt的安装目录下\Examples\Qt-5.11.2\webchannel\shared\qwebchannel.js,直接copy&paste就完事了,在index.html里用<script>标签引用一下,这就是前端的工作了,而且工作量并不大,而且很简单所以就不多说了。

其次就是Dialog和Core这俩压根没找到实现的类,我经过了各种可能的猜测,其中Dialog最好理解,就是那个窗口嘛,而我给的DEMO直接上控制台(Console)就可以了,压根不需要对话框这个多余的东西,不过官方可能也是让我们方便调试才用的图形化窗口。但就连Core都不提供就不能忍了,刚开始看这东西我完全是懵逼状态的,这是个啥啊?后来分析了也猜了好久才明白,这是个连接类,这还得结合JS端来分析,单从C++的角度来分析那是作死,反正我已经作过死了,不能让我们的读者朋友们继续作死了,所以这里重点讲一下Core连接类,当然我自己的DEMO并不是这么写的。

接下来就是实现部分了,从0到1的实现通过QWebChannel让C++与JS端进行交互的编程(这名字我自己都有点受不了,不管了,重点在内容)。

首先我先建一个基于控制台的Qt应用程序,构建组件那块一定要选择MinGW

接下来我们把Qt安装目录下的Examples\Qt-5.11.2\webchannel\shared下的文件全部复制到工程目录下,顺便建一个index.html

然后在Qt中将cpp与h文件全部导入进工程中

打开pro文件,里面加入QT += core websockets webchannel

main.cpp文件里包含websocketclientwrapper.h、websockettransport.h、<QtWebChannel/QWebChannel>、<QtWebSockets/QWebSocketServer>

这样,初始化的工作就基本结束了,我们要通过WebSocket与WebChannel让C++与JS达成交互的目的。

在main.cpp的QCoreApplication a(argc, argv);与return a.exec();之间写上以下代码

    QWebSocketServer server(QStringLiteral("QWebChannel Standalone Example Server"),
                            QWebSocketServer::NonSecureMode);
    if (!server.listen(QHostAddress::LocalHost, 12345)) {
        qFatal("Failed to open web socket server.");
        return 1;
    }

    // wrap WebSocket clients in QWebChannelAbstractTransport objects
    WebSocketClientWrapper clientWrapper(&server);

    // setup the channel
    QWebChannel channel;
    QObject::connect(&clientWrapper, &WebSocketClientWrapper::clientConnected,
                     &channel, &QWebChannel::connectTo);

    // setup the dialog and publish it to the QWebChannel
    ChatServer* chatserver = new ChatServer(&a);
    channel.registerObject(QStringLiteral("chatserver"), chatserver);

别问我WebSocketClientWrapper是干嘛用的,这我也不清楚,我只知道这样的代码能用。。。

现在要实现ChatServer类了。

在实现之前我们要知道这个Core是个连接类,用于连接C++与JS的,在这里ChatServer起着与Core一样的作用,但是如何来实现呢?

这点就是我研究了几个小时来的成果了,提一个关键字“元数据”。Qt里有一个宏叫Q_INVOKABLE可以用于声明元数据,只要是声明了元数据的公共函数就可以被JS端所调用。

现在我上代码了

chatserver.h

#ifndef CHATSERVER_H
#define CHATSERVER_H

#include <QObject>

class ChatServer : public QObject
{
    Q_OBJECT

public:
    explicit ChatServer(QObject *parent = nullptr);
    virtual ~ChatServer();

    Q_INVOKABLE void test1();

signals:
    void test2();
};

#endif // CHATSERVER_H

chatserver.cpp

#include "chatserver.h"
#include <QDebug>

ChatServer::ChatServer(QObject *parent)
    : QObject(parent)
{}

ChatServer::~ChatServer()
{}

void ChatServer::test1() {
    qDebug() << "This is test1";
}

index.html

<!DOCTYPE html>
<html>
<head>
    <title>ChatClient</title>

    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script type="text/javascript" src="qwebchannel.js"></script>

    <script>
        'use strict';
        var wsUri = "ws://localhost:12345";
        window.onload = function() {
            var socket = new WebSocket(wsUri);
            socket.onclose = function() {
                console.error("web channel closed");
            };
            socket.onerror = function(error) {
                console.error("web channel error: " + error);
            };
            socket.onopen = function() {
                window.channel = new QWebChannel(socket, function(channel) {
					channel.objects.chatserver.test1();
                });
            }
        }
    </script>
</head>
<body>
</body>
</html>

有了上面的代码,编译运行C++端,等黑窗口出来后打开index.html访问网页,回到C++端就会发现“This is test1”字符串,这就说明我们成功的从JS端调用C++的函数了。

这里我解释一下,在C++端channel.registerObject(QStringLiteral("chatserver"), chatserver);就等于是在注册元数据信息,让JS端可以访问到元数据,名称可以把字符串的chatserver改成其他的,比如core变成:channel.registerObject(QStringLiteral("core"), chatserver);

在JS端把chatserver改成core,再编译运行C++端,然后打开index.html发现依然可以输出“This is test1”字符串,就表示QStringLiteral("XXXX")是可以指定暴露给JS端的元数据名称的,而后面的chatserver或是core都是连接类了,暴露给JS端的类。

跑完了JS端调用C++端的,再看看C++调用JS端的,这其实也挺简单的,在C++上建立一个信号,emit一个信号,在JS端绑定信号就可以用于接收C++的信号了,从而实现C++调用JS函数的效果。这说起来可能有点晕,直接上代码。

这回只需要JS端的代码了,因为C++端的上面已经有了,也就是signals一个信号出来,在JS端连接一下。

socket.onopen = function() {
    window.channel = new QWebChannel(socket, function(channel) {
        channel.objects.core.test2.connect(function () {
            console.log('aaaa');
        });
        channel.objects.core.test1();
    });
}

我们在test1函数中emit一下test2

void ChatServer::test1() {
    qDebug() << "This is test1";
    emit test2();
}

编译C++端并运行,然后打开index.html,按F12点击控制台选项,看到了aaaa,说明从C++端调用JS函数也是没问题的

总结

C++端相当于是服务端,JS端相当于是客户端

C++的元数据可供JS端访问,触发信号可调用JS端函数

 

不知道各位网友有没有看懂呢?如果还有不明白的可以留言,反正我也不一定知道,但知道的还是会尽量解答一下的,我只能尽我所能了。希望这篇文章能帮助到那些遇到QWebChannel的坑,和我一样半天过不去的猿们。。。

  • 1
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
QWebChannel是一种用于Qt应用程序和嵌入式Web页面之间进行互操作的通信机制。它允许Qt应用程序向Web页面暴露对象,并允许Web页面访问这些对象的属性和方法。同时,也允许Web页面向Qt应用程序发送消息和调用Qt应用程序的函数。 使用QWebChannel进行Qt和JavaScript之间的交互,需要遵循以下步骤: 1. 在Qt应用程序中创建一个QWebChannel对象,并将其绑定到一个QWebEngineView或QWebEnginePage对象上。 2. 在Qt应用程序中创建一个QObject的子类,该子类将作为Qt对象被暴露给Web页面。 3. 在Qt应用程序中将QObject对象注册到QWebChannel对象中。 4. 将QWebChannel对象传递给Web页面,通过JavaScript代码将其绑定到Web页面中的window对象上。 5. 在JavaScript代码中可以通过window对象访问到Qt应用程序中注册的QObject对象,调用其属性和方法。 6. 在Qt应用程序中可以通过QWebChannel对象接收Web页面发送的消息,以及调用Web页面中的JavaScript函数。 下面是一个简单的例子,演示了如何使用QWebChannel进行Qt和JavaScript之间的交互Qt代码: ```c++ // 创建一个QObject的子类,作为Qt对象被暴露给Web页面 class MyObject : public QObject { Q_OBJECT public: MyObject(QObject *parent = nullptr) : QObject(parent) {} public slots: void showMessage(const QString &message) { qDebug() << "Received message from web page:" << message; } }; int main(int argc, char *argv[]) { QApplication app(argc, argv); // 创建一个QWebChannel对象,并将其绑定到一个QWebEngineView对象上 QWebEngineView view; QWebChannel channel; view.page()->setWebChannel(&channel); // 创建MyObject对象,并将其注册到QWebChannel对象中 MyObject obj; channel.registerObject("myObject", &obj); // 加载Web页面 view.load(QUrl("qrc:/index.html")); view.show(); return app.exec(); } ``` JavaScript代码: ```javascript // 将QWebChannel对象绑定到window对象上 new QWebChannel(qt.webChannelTransport, function(channel) { window.myObject = channel.objects.myObject; }); // 调用MyObject对象的showMessage函数 myObject.showMessage("Hello from web page!"); ``` 在上面的例子中,我们创建了一个名为MyObject的QObject子类,并将其注册到了QWebChannel对象中。在JavaScript代码中,我们通过调用QWebChannel构造函数,将QWebChannel对象绑定到window对象上,并通过window对象访问了MyObject对象的showMessage函数。当Web页面调用showMessage函数时,它将向Qt应用程序发送一个消息,Qt应用程序将通过QWebChannel对象接收到该消息,并调用MyObject对象的showMessage函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值