最清晰Qt与JS通过qwebchannel交互例子

tags: Qt javascript qwebchannel QWebEngineView


由来

在Qt平台上有很多很棒的图表控件,比如QWT,QCustomPlot,以及Qt5.5以后自带的QChart,但与JS网页端的各种绚丽效果控件比,还是差了不少。这次就是打算把百度出品的EChart控件应用在Qt端。
而在这样的跨平台调用中,很多文章都写的含糊其词,让人晕头转向,于是写一篇记录下最清晰最简单的调用过程。

工具

Qt5.5以上,在安装时选择上QWebEngine
同时必须选择基于VS编译器的Qt版本,基于MinGW的编译不能通过,原因可能是GCC不支持QWebEngine。
在这里插入图片描述

工程配置

1.新建基于Widget的工程
2..pro里加入

QT       += core gui webenginewidgets webchannel

.h里引用头文件

#include <QWebEngineView>
#include <QtWebChannel>

3.从QObjec派生一个类

class WebClass : public QObject
{
    Q_OBJECT
public slots:
    void jscallme()
    {
        QMessageBox::information(NULL, "jscallme", "jscallme");
    }
};

MainWindow的类里声明变量

    QWebEngineView *webView = nullptr;
    QWebChannel *webChannel = nullptr;

MainWindow.cpp里初始化变量

    webView = new QWebEngineView(parent);
    webView->load(QUrl::fromLocalFile("D:\\Code\\EChartTest\\test.html"));
    mainLayout->addWidget(webView);
    webChannel = new QWebChannel;
    WebClass *webobj = new WebClass();
    webChannel->registerObject("webobj", webobj);
    webView->page()->setWebChannel(webChannel);

4.用文本编辑器新建一个test.html文件,内容写:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title></title>
</head>
<body>
  <script src="qwebchannel.js"></script> 
  <script type="text/javascript">
  new QWebChannel(qt.webChannelTransport,
  function(channel){
  var webobj = channel.objects.webobj;
  window.foo = webobj;
  webobj.jscallme();
  });
  </script>
</body>
</html>

5.将Qt目录"C:\Qt\Qt5.12.1\Examples\Qt-5.12.1\webchannel\shared"下的qwebchannel.js文件拷贝到上面的test.html目录下
6.好了,Qt端 运行程序。
7.结果为HTML的程序调用了C++的函数。

JS传递给C++

再进一步吧/
1.修改
void jscallme()

void jscallme(const QString &text)
{
    QMessageBox::information(NULL, "jscallme", text);
}

2.HTML端修改webobj.jscallme();webobj.jscallme('中文调用');
3.右键点击下Qt端的程序,reload后,弹出结果
4.每次都这样通过C++端函数赋值太麻烦了,可以直接在JS里给C++端变量赋值就好了。也简单,修改派生的类。

class WebClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString content MEMBER m_content)
public slots:
    void jscallme()
    {
        QMessageBox::information(NULL, "jscallme", m_content);
    }

private:
    QString m_content;
}

5.修改HTML端

  new QWebChannel(qt.webChannelTransport,
  function(channel){
  var webobj = channel.objects.webobj;
  window.foo = webobj;
  webobj.content = 'sdfef中文';
  webobj.jscallme();
  });

6.reload下Qt端程序,结果符合预期

c++传递到JS

1.修改派生类

 Q_PROPERTY(QString content MEMBER m_content NOTIFY contentChanged)

2.修改HTML端

  <script type="text/javascript">

var updateattribute=function(text)
{	
	document.write(text);	
}

  new QWebChannel(qt.webChannelTransport,
  function(channel){
  var webobj = channel.objects.webobj;
  window.foo = webobj;
  webobj.contentChanged.connect(updateattribute);

  });

  
  </script>

3.Qt程序上放个按钮,按钮按下事件里写:
webobj->setProperty("content", "453453453");
4.Qt程序上的webview会刷新出结果.

传递自定义结构数据

上面的例子里都是传递基本类型,如果我自己定义的数据类型怎么办呢?比如

struct Data
{
    int a;
    double b;
    QString str;
};

可惜花了一整天也没搞清楚怎么传递这样的结构,各种宏绕的头晕,有明白的同学请留言指教。
不过我却发现了通过QJsonObject来传递的简单方法,将上面的结构用QJSonObject重写就可以了,具体代码如下
Qt端类声明

class WebClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QJsonObject jsonData MEMBER m_jsonData NOTIFY dataChanged)
public:
signals:

    void dataChanged(const QJsonObject &jsonData);
private:
    QJsonObject m_jsonData;
};

Qt端主函数

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    btn = new QPushButton("..");
    connect(btn, &QPushButton::clicked, this,
            [&]()
    {
        QJsonObject json;
		json["a"] = 2;
        json["b"] = 3.336;
        json["c"] = "sdef";
        webobj->setProperty("jsonData", json);
    });
    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(btn, 1, Qt::AlignLeft);

    webView = new QWebEngineView(parent);
    webView->load(QUrl::fromLocalFile("D:\\Code\\JS\\test.html"));
    layout->addWidget(webView);
    QWidget *w = new QWidget;
    w->setLayout(layout);

    setCentralWidget(w);

    webChannel = new QWebChannel;
    webobj = new WebClass();
    webChannel->registerObject("webobj", webobj);
    webView->page()->setWebChannel(webChannel);
    setMinimumSize(800, 600);
}

HTML端代码如下

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
    <meta charset="utf-8">
    <!-- 引入 ECharts 文件 -->
    <script src="D:/Code/JS/Echart/echarts.min.js"></script>
</head>
<p id="x">x:</p>
<p id="y">y:</p>
<body>
    <script src="qwebchannel.js"></script>
    <script type="text/javascript">
       
        new QWebChannel(qt.webChannelTransport, function (channel) {
                var webobj = channel.objects.webobj;
             
                webobj.dataChanged.connect(function (arg) { 
                    x.innerHTML = "x:" + arg.x ;
                    y.innerHTML = "y:" + arg.y.toFixed(4);
                });

            });
    </script>
    
</body>

</html>

好了,自定义结构传递效果如下
GI2F.gif

更进一步

在下一步里直接用Qt生成随机数,通过QWebChannel发送到JS端,调用echarts控件显示曲线。
Qt调用Echarts显示动态过程曲线

参考文献

Communication between C++ and Javascript in Qt WebEngine

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页