Qt与JS数据交互

QT版本:5.6.2

核心类:QWebEngineView, QWebChannel 

1、C++和HTML通过websocket通信,通过官方的 qwebchannel.js 实现。

2、C++和HTML共用一个对象并以此进行通信,即通过QWebChannel的registerObject函数。
void QWebChannel::registerObject(const QString &id, QObject *object)

3、C++通知HTML:通过信号将数据传给JS(例如signalToWeb), 故可发送信息。

4、HTML通知C++:直接调用槽函数(必须是槽函数)
 
5、如果有多处使用了QWebEngineView, 则多个QWebEngineView可以共享同一个QWebChannel,因此可以讲QWebChannel定义为一个全局的单例对象,并通过其注册多个Cpp对象。
void QWebEnginePage::setWebChannel(QWebChannel *channel);
m_webEngineView->page()->setWebChannel(m_webChannel);

6、重要:
1)触发发送信号(例如signalToWeb)的按钮不要放在设计师界面,因为UI模式的点击事件上发信号在该组件会出现无法响应的bug(5.7.1)。
2)在给HTML传数据之前,要确保其已经load加载完成了,因为load和setUrl都是异步的,所以需要使用信号-槽连接(在槽里面完成数据的传送)。
void QWebEngineView::load(const QUrl &url)
void QWebEngineView::setUrl(const QUrl &url)
connect(m_webEngineView, SIGNAL(loadFinished(bool)), this, SLOT(slotSendDataToH5(bool)));

m_webEngineView->setUrl(QUrl("D:/testJsCallCpp/resources/index.html"));

C++代码:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QWebEngineProfile>
#include <QWebEngineView>
#include <QWebChannel>

#include "document.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    QJsonObject getUserInfoFromCpp();

private slots:
    void slotSendDataToH5(bool ok);

private:
    Ui::MainWindow *ui;

    QWebEngineView *m_webEngineView;
    QWebChannel *m_webChannel;
    Document m_content;
};

#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"

const QString HttpUserAgent_H5 = QString("Toon-pc/1.0.0 windows,android,iphone,ipad");

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    m_webEngineView = new QWebEngineView();
    m_webEngineView->setContextMenuPolicy(Qt::NoContextMenu);
    m_webChannel = new QWebChannel();

    m_webChannel->registerObject(QStringLiteral("cppObject"), &m_content);
    m_webEngineView->page()->setWebChannel(m_webChannel);
    m_webEngineView->page()->profile()->setHttpUserAgent(HttpUserAgent_H5);

    connect(m_webEngineView, SIGNAL(loadFinished(bool)), this, SLOT(slotSendDataToH5(bool)));
    //m_webEngineView->setUrl(QUrl("https://www.baidu.com"));
    m_webEngineView->setUrl(QUrl("D:/testJsCallCpp/resources/index.html"));

    this->setCentralWidget(m_webEngineView);
}

MainWindow::~MainWindow()
{
    delete ui;
}

QJsonObject MainWindow::getUserInfoFromCpp()
{
    QJsonObject json;
    json.insert("header", QStringLiteral("I am Qt!"));
    return json;
}

void MainWindow::slotSendDataToH5(bool ok)
{
    if (ok)
        m_content.sendJsonToWeb(getUserInfoFromCpp());
    else
        qDebug()<<"load failed! ok="<<ok;
}
#ifndef DOCUMENT_H
#define DOCUMENT_H

#include <QDebug>
#include <QObject>
#include <QJsonObject>

Q_DECLARE_METATYPE(QJsonObject)

class Document : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QJsonObject m_json READ getJson NOTIFY signalToWeb)

public:
    explicit Document(QObject *parent = nullptr) : QObject(parent)
    {
        qRegisterMetaType<QJsonObject>("QJsonObject");
    }


    QJsonObject getJson() const
    {
        return m_json;
    }

    // cpp端直接通过对象调用
    void sendJsonToWeb(const QJsonObject &json)
    {
        if (m_json != json)
        {
            m_json = json;
            emit signalToWeb(json);
        }
    }

signals:
    void receiveTextFromWeb(const QString &text);

    // js端通过注册的对象ID调用
public slots:
    // 必须为槽函数
    void sendTextToCpp(const QString &text)
    {
        qDebug()<<"******from web*******text="<<text;
        emit receiveTextFromWeb(text);
    }

signals:
    void signalToWeb(const QJsonObject &json);

private:
    QJsonObject m_json;
};

#endif // DOCUMENT_H

HTML代码:

<!doctype html>
<html lang="en">
<meta charset="utf-8">
<head>
  <link rel="stylesheet" type="text/css" href="markdown.css">
  <script src="marked.min.js"></script>
  <script src="qwebchannel.js"></script>
</head>
<body>
  <div id="placeholder"></div>
  <script>
  'use strict';

            window.onload = function() {
                if (navigator.userAgent.indexOf('Toon-pc') !== -1) {
                    
                    new QWebChannel(window.qt.webChannelTransport, function (channel) {
                        window.bridge = channel.objects.cppObject

                        // cpp通过signalToWeb信号给web传值:response
                        bridge.signalToWeb.connect(function (response) {
                            window.alert(response.header);
                        })
                    })
                }
            }
			
			function fromWebToCpp()
			{
			    // web调用cpp的 sendTextToCpp 方法,并带上参数
                bridge.sendTextToCpp(JSON.stringify({
                    userId: 100
                }))
			}			
  </script>
  <body>
  <input id="add" type="button" value="传值给Cpp" class="button" onclick="fromWebToCpp();"/>
  </body>
</body>
</html>

运行效果:



猜你喜欢

转载自blog.csdn.net/e5max/article/details/80004873