QML WebEngine + ECharts展示实时曲线

(相信不少人都会用 ECharts 这个网页图表库,我这里也只是学 WebEngine 顺带做个笔记)

我的环境:Qt5.15.1 MSVC 32bit,不同的版本可能 webengine 的初始化有所不同,以官方文档为准。

本文完整项目链接:https://github.com/gongjianbo/MyTestCode/tree/master/Qml/QmlWebEngineECharts

0.下载ECharts

下载地址:https://echarts.apache.org/zh/download.html

提供了三种方式的下载:

方法一:从下载的源代码或编译产物安装

方法二:从 npm 安装

方法三:选择需要的模块,在线定制下载

这里我选择的定制下载:https://echarts.apache.org/zh/builder.html ,选择自己所需模块后就可以下载单个 js 文件。

1.QML WebEngine使用ECharts

WebEngine 初始化步骤参照文档:https://doc.qt.io/qt-5/qml-qtwebengine-webengineview.html

pro 文件加上 webengine 模块:

QT += webengine
   
   

main.cpp 文件初始化 webengine 相关:


   
   
  1. //#include <qtwebengineglobal.h>
  2. // 因为5.13的在线文档没了,所以我没法判断,请自己查下文档
  3. #if (QT_VERSION >= QT_VERSION_CHECK(5,14,0))
  4. QCoreApplication:: setAttribute(Qt::AA_ShareOpenGLContexts);
  5. // 有些情况可能需要soft opengl
  6. QCoreApplication:: setAttribute(Qt::AA_UseSoftwareOpenGL);
  7. // webengine须初始化,5.12放在app构造后,5.15放在构造前
  8. QtWebEngine:: initialize();
  9. QGuiApplication app(argc, argv);
  10. #else
  11. // 5.12提示Attribute Qt::AA_ShareOpenGLContexts must be set before QCoreApplication is created
  12. QCoreApplication:: setAttribute(Qt::AA_ShareOpenGLContexts);
  13. // 有些情况可能需要soft opengl
  14. //QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
  15. // webengine须初始化,5.12放在app构造后,5.15放在构造前
  16. QGuiApplication app(argc, argv);
  17. QtWebEngine:: initialize();
  18. #endif

从 ECharts 的官方示例拷贝实时曲线的例程:https://echarts.apache.org/examples/zh/editor.html?c=dynamic-data2

将例程放到 html 文件中,参照:ECharts官方教程 ,由于比较长,我就放到下一节以及 github 链接了(我把 echarts.js 和 index.html 放在了单独的文件夹,pro DESTDIR 也指定到了该目录)。

最后把 qml 文件改改就能运行了:


   
   
  1. import QtQuick 2.12
  2. import QtQuick. Window 2.12
  3. import QtWebEngine 1.2
  4. Window {
  5. width: 640
  6. height: 480
  7. visible: true
  8. title: qsTr( "WebEngine + ECharts (By: GongJianBo1992)")
  9. WebEngineView{
  10. anchors. fill: parent
  11. //@disable-check M7
  12. url: "file:///./index.html"
  13. }
  14. }

尽量用 release 跑, debug 模式很容易崩溃。还有就是有些环境可能需要设置 AA_UseSoftwareOpenGL 才能正常运行,但是这又导致持续动态刷新很占 cpu。

2.传递数据到 html ,实时刷新曲线

webengine 传递数据到 html 还是比较方便的,可以直接调用 js 函数传递参数,也可以用 websocket,或者 ajax 请求数据。这里我使用的调用 js 函数传递 JSON 参数。

webengineview 提供了 runJavaScript 函数在 web 中执行脚本:

void runJavaScript(string script, variant callback)
   
   

最终效果:

下面是 html 和 qml 的代码:

完整项目链接:https://github.com/gongjianbo/MyTestCode/tree/master/Qml/QmlWebEngineECharts


   
   
  1. import QtQuick 2.12
  2. import QtQuick. Window 2.12
  3. import QtQuick. Controls 2.12
  4. import QtWebEngine 1.2
  5. Window {
  6. id: root
  7. width: 640
  8. height: 480
  9. visible: true
  10. title: qsTr( "WebEngine + ECharts (By: GongJianBo1992)")
  11. property var now: new Date( 1997, 9, 3)
  12. property var oneDay: 24 * 3600 * 1000
  13. WebEngineView{
  14. id: view
  15. anchors. fill: parent
  16. //@disable-check M7
  17. url: "file:///./index.html"
  18. }
  19. Row{
  20. anchors. right: parent. right
  21. anchors. top: parent. top
  22. anchors. margins: 10
  23. spacing: 10
  24. Button{
  25. text: "单个数据"
  26. onClicked: {
  27. now = new Date(+now + oneDay);
  28. view. runJavaScript( "window.appendData("+
  29. JSON. stringify({
  30. "date":now. valueOf(),
  31. "value": Number( Math. random() * 1000 + 500)
  32. })+ ")");
  33. }
  34. }
  35. Button{
  36. text: "批量数据"
  37. onClicked: {
  38. let datalist=[];
  39. for( let i= 0;i< 100;i++)
  40. {
  41. now = new Date(+now + oneDay);
  42. datalist. push({ "date":now. valueOf(), "value": Number( Math. random() * 1000 + 500)});
  43. }
  44. view. runJavaScript( "window.setData("+
  45. JSON. stringify(datalist)+ ")");
  46. }
  47. }
  48. }
  49. }

   
   
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Document </title>
  7. <style>
  8. html,
  9. body,
  10. #echarts {
  11. margin: 0px;
  12. padding: 0px;
  13. width: 100%;
  14. height: 100%;
  15. }
  16. </style>
  17. </head>
  18. <body>
  19. <div id="echarts"> </div>
  20. <!-- 引入 echarts -->
  21. <script src="./echarts.min.js"> </script>
  22. <script>
  23. //每次now+一天
  24. function randomData( ) {
  25. now = new Date(+now + oneDay);
  26. //name给标签用,value是x-y坐标点
  27. return {
  28. name: now. toString(),
  29. value: [now, Math. random() * 1000 + 500]
  30. };
  31. }
  32. //新的数据
  33. function newData( dataitem) {
  34. now = new Date(dataitem. date);
  35. return {
  36. name: now. toString(),
  37. value: [now, dataitem. value]
  38. };
  39. }
  40. var myChart = echarts. init( document. getElementById( 'echarts'));
  41. var data = [];
  42. var now = + new Date( 1970, 1, 1);
  43. var oneDay = 24 * 3600 * 1000;
  44. myChart. setOption({
  45. title: {
  46. text: '动态数据 + 时间坐标轴'
  47. },
  48. tooltip: {
  49. trigger: 'axis',
  50. formatter: function ( params) {
  51. params = params[ 0];
  52. var date = new Date(params. name);
  53. return date. getDate() + '/' + (date. getMonth() + 1) + '/' + date. getFullYear() + ' : ' +
  54. params. value[ 1];
  55. },
  56. axisPointer: {
  57. animation: false
  58. }
  59. },
  60. xAxis: {
  61. type: 'time',
  62. min: now - 100 * oneDay,
  63. max: now,
  64. splitLine: {
  65. show: false
  66. }
  67. },
  68. yAxis: {
  69. type: 'value',
  70. min: 0,
  71. max: 2000,
  72. boundaryGap: [ 0, '100%'],
  73. splitLine: {
  74. show: false
  75. }
  76. },
  77. series: [{
  78. name: '模拟数据',
  79. type: 'line',
  80. showSymbol: false,
  81. hoverAnimation: false,
  82. data: data
  83. }]
  84. });
  85. //刷新数据
  86. function updateData( ) {
  87. myChart. setOption({
  88. xAxis: {
  89. type: 'time',
  90. min: now - 100 * oneDay,
  91. max: now
  92. },
  93. series: [{
  94. data: data
  95. }]
  96. });
  97. }
  98. //定时填充数据
  99. //每次数据x加一天,范围为100天
  100. /*setInterval(function () {
  101. if (data.length > 100)
  102. data.shift();
  103. data.push(randomData());
  104. updateData();
  105. }, 200);*/
  106. //我们定义dataitem结构为[date,value]
  107. //添加单个数据
  108. function appendData( dataitem) {
  109. if (data. length > 100)
  110. data. shift();
  111. data. push( newData(dataitem));
  112. updateData();
  113. }
  114. //添加批量数据
  115. function setData( datalist) {
  116. if (datalist. length <= 0)
  117. return;
  118. while (datalist. length > 100)
  119. datalist. shift();
  120. data = [];
  121. for ( var i = 0; i < datalist. length; i++)
  122. data. push( newData(datalist[i]));
  123. updateData();
  124. }
  125. //自适应大小
  126. window. addEventListener( "resize", function ( ) {
  127. myChart. resize();
  128. });
  129. </script>
  130. </body>
  131. </html>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QML中,可以通过C++来注入一个对象供QML使用。这个过程涉及到以下几个步骤: 1. 创建一个C++类,该类将作为注入给QML使用的对象。这个类需要继承自QObject,并且需要使用Q_OBJECT宏进行声明,以支持信号与槽的机制。 2. 在C++类中,可以定义一些属性、方法和信号,这些将在QML中被调用和访问。 3. 在main函数中,创建一个QGuiApplication或者QApplication实例,并注册C++类到QML引擎中。可以使用qmlRegisterType函数来完成注册,该函数需要传入C++类的名称、命名空间、版本号等信息。 4. 在QML文件中,通过import语句导入C++类所在的命名空间,并且可以直接使用该类的实例。 下面是一个示例代码,演示了如何在QML中注入一个C++对象供使用: ```cpp // MyObject.h #ifndef MYOBJECT_H #define MYOBJECT_H #include <QObject> class MyObject : public QObject { Q_OBJECT Q_PROPERTY(QString message READ message WRITE setMessage NOTIFY messageChanged) public: explicit MyObject(QObject *parent = nullptr); QString message() const; void setMessage(const QString &message); signals: void messageChanged(); private: QString m_message; }; #endif // MYOBJECT_H ``` ```cpp // MyObject.cpp #include "MyObject.h" MyObject::MyObject(QObject *parent) : QObject(parent) { } QString MyObject::message() const { return m_message; } void MyObject::setMessage(const QString &message) { if (m_message != message) { m_message = message; emit messageChanged(); } } ``` ```cpp // main.cpp #include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include "MyObject.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; // 注册C++类到QML引擎中 qmlRegisterType<MyObject>("com.example", 1, 0, "MyObject"); MyObject myObject; myObject.setMessage("Hello from C++!"); // 将C++对象设置为上下文属性,以便在QML中使用 engine.rootContext()->setContextProperty("myObject", &myObject); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); } ``` ```qml // main.qml import QtQuick 2.15 import com.example 1.0 Item { width: 200 height: 200 Text { text: myObject.message anchors.centerIn: parent } } ``` 在上面的示例中,我们创建了一个名为MyObject的C++类,并在QML中使用了它的message属性。在main函数中,我们注册了MyObject类,并将其实例设置为上下文属性,以便在QML中访问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值