QT有图表库,用来展示数据,比如QWT,QCustomPlot,QChart。QCustomPlot是一相对好用的轻量级的控件,QChart虽然说是QT框架内的,可是听说性能极差,完全比不上QCustomPlot,而QWT是一个性能比较好的,且样式也相比其它两个来说,是相对丰富,重量级的库,可是需要自己编译配置环境,如果感兴趣可以查看我其它的博客怎么来编译它。这里我都不讲以上三个库,下面我相讲的是QT怎么来结合EChart做开发。
而EChart是一个很好的js图表库,图表丰富,又好看,毕竟它不是QT体系内的,性能不知道怎样,但是如果数据不多,我们完全可以用它来展示,可是在QT中怎么调用它呢?
我们知道QT4有一个QWebView可以用来操作网页,在QT5中则使用QWebEngineView。下面我来讲一下具体操作。
一、QT加载ECharts
1,下载ECharts.js库
官网下载http://echarts.baidu.com/download.html
2. 编写.html加载echart.
可以从官网的example里下载代码示例
https://echarts.baidu.com/examples/
然后点击一个示例,就可以打开示例页面,然后在示例页面右下角点击“Download"按钮,即可将示例代码下载下来。
3.新建一个工程
4.在QT工程下新建一文件夹,并将echarts.js或,echarts.min.js和前面下载的示例html文件,放入同一文件夹中。
5 更改示例html文件内容,如下,(其中一定要注意加载echarts.js的路径)会前端开发的一下就能看明白,但对于每一个程序员来说,这些代码也不难懂,非常简单。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>ECharts</title> <!-- 引入 echarts.js --> <script src="./echarts.js"></script> </head> <body> <!-- 为ECharts准备一个具备大小(宽高)的Dom --> <div id="main" style="width: 750px;height:450px;"></div> <script type="text/javascript"> // 基于准备好的dom,初始化echarts实例 var myChart = echarts.init(document.getElementById('main')); var option = { title: { text: "对数轴示例", x: "center" }, tooltip: { trigger: "item", formatter: "{a} <br/>{b} : {c}" }, legend: { x: 'left', data: ["2的指数", "3的指数"] }, xAxis: [ { type: "category", name: "x", splitLine: {show: false}, data: ["一", "二", "三", "四", "五", "六", "七", "八", "九"] } ], yAxis: [ { type: "log", name: "y" } ], toolbox: { show: true, feature: { mark: { show: true }, dataView: { show: true, readOnly: true }, restore: { show: true }, saveAsImage: { show: true } } }, calculable: true, series: [ { name: "3的指数", type: "line", data: [1, 3, 9, 27, 81, 247, 741, 1223, 5669] }, { name: "2的指数", type: "line", data: [1, 2, 4, 8, 16, 32, 64, 228, 156] } ] }; myChart.setOption(option); </script> </body> </html>5. 左qt工程中,双击打开界面ui,在UI编辑器中添加一个widget,并将widget提升为“QWebEngineView”(这里是以QT5.9.3为例)
6.然后再mainwindow.cpp中添加如下代码,以运行QWebEngineView来加载刚刚改好的.html页面。
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); ui->widget->setContextMenuPolicy(Qt::NoContextMenu); ui->widget->load(QUrl("E:/workspace/QT_PRJ/echartsTest/htmlEcharts/testEcharts.html")); }好了,到这里就可以显示出一个加载了echarts的html页面了。
二、QT与ECharts交互
上面我们已经知道,QT是通过QWebEngineView来调用HTML页面的,而在HTML中通过JS来调用ECharts。
1.封装设置ECharts属性的JS方法
QT可以通过QWebEngineView调用加载的html页面中的JS方法,所以我们要将.HTML页面中JS设置ECharts属性的那段代码封装成一个方法
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>ECharts</title> <!-- 引入 echarts.js --> <script src="./echarts.js"></script> </head> <body> <!-- 为ECharts准备一个具备大小(宽高)的Dom --> <div id="main" style="width: 750px;height:450px;"></div> <script type="text/javascript"> // 基于准备好的dom,初始化echarts实例 var myChart = echarts.init(document.getElementById('main')); function init(){ var option = { title: { text: "对数轴示例", x: "center" }, tooltip: { trigger: "item", formatter: "{a} <br/>{b} : {c}" }, legend: { x: 'left', data: ["2的指数", "3的指数"] }, xAxis: [ { type: "category", name: "x", splitLine: {show: false}, data: ["一", "二", "三", "四", "五", "六", "七", "八", "九"] } ], yAxis: [ { type: "log", name: "y" } ], toolbox: { show: true, feature: { mark: { show: true }, dataView: { show: true, readOnly: true }, restore: { show: true }, saveAsImage: { show: true } } }, calculable: true, series: [ { name: "3的指数", type: "line", data: [0, 0, 0, 0, 0, 0, 0, 0, 0] }, { name: "2的指数", type: "line", data: [0, 0, 0, 0, 0, 0, 0, 0, 0] } ] }; myChart.setOption(option); } init(); </script> </body> </html>可以看到,我将设置属性封装成了一个方法,然后再自调用了一次,可以保证在执行程序初始化的时候可以显示出图表,其中我将加载的数据都设置成了0,所以显示的是一个空的图表,看不到曲线。
2.封装带参数设置ECharts属性的JS方法
QT与EChart交互得传递数据,那么我们只封装了一个不带参数的方法是不能从外面设置数据的,我们可以封装成了一个带参数的方法,这个参数则是我们要显示的数据,这个参数我们用JSON的格式来传递,它可以传递多条曲线的数据。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>ECharts</title> <!-- 引入 echarts.js --> <script src="./echarts.js"></script> </head> <body> <!-- 为ECharts准备一个具备大小(宽高)的Dom --> <div id="main" style="width: 750px;height:450px;"></div> <script type="text/javascript"> // 基于准备好的dom,初始化echarts实例 var myChart = echarts.init(document.getElementById('main')); function init(){ var option = { title: { text: "对数轴示例", x: "center" }, tooltip: { trigger: "item", formatter: "{a} <br/>{b} : {c}" }, legend: { x: 'left', data: ["2的指数", "3的指数"] }, xAxis: [ { type: "category", name: "x", splitLine: {show: false}, data: ["一", "二", "三", "四", "五", "六", "七", "八", "九"] } ], yAxis: [ { type: "log", name: "y" } ], toolbox: { show: true, feature: { mark: { show: true }, dataView: { show: true, readOnly: true }, restore: { show: true }, saveAsImage: { show: true } } }, calculable: true, series: [ { name: "3的指数", type: "line", data: [0, 0, 0, 0, 0, 0, 0, 0, 0] }, { name: "2的指数", type: "line", data: [0, 0, 0, 0, 0, 0, 0, 0, 0] } ] }; myChart.setOption(option); } function init2(str){ var option = { title: { text: "对数轴示例", x: "center" }, tooltip: { trigger: "item", formatter: "{a} <br/>{b} : {c}" }, legend: { x: 'left', data: ["2的指数", "3的指数"] }, xAxis: [ { type: "category", name: "x", splitLine: {show: false}, data: ["一", "二", "三", "四", "五", "六", "七", "八", "九"] } ], yAxis: [ { type: "log", name: "y" } ], toolbox: { show: true, feature: { mark: { show: true }, dataView: { show: true, readOnly: true }, restore: { show: true }, saveAsImage: { show: true } } }, calculable: true, series: [ { name: "3的指数", type: "line", data: str["data1"] }, { name: "2的指数", type: "line", data: str["data2"] } ] }; myChart.setOption(option); } window.onresize = myChart.resize ; init(); </script> </body> </html>3.QT调用JS方法显示数据
1)QWebEngineView可以调用它的page()->runJavaScript("function(str)")来运行JS方法。
2)在QT中我们需要组成一个JSON字符串将数据传过去,所以我们需要用到QJonsObject来组成一个JSON对象,使用QJsonArray往JSON对象中添加一数组,使用QJsonDocument来将JSON对象转化成字符串。
接下来在QT工程中的UI界面中增加一个QPushButton并添加信号和槽函数,在槽函数中添加如下代码
void MainWindow::on_test2_clicked() { QJsonObject seriesData; QJsonArray data1 = {1, 3, 9, 27, 81, 247, 741, 2223, 6669}; seriesData.insert("data1", data1); QJsonArray data2 = {1, 2, 4, 8, 16, 32, 64, 128, 256}; seriesData.insert("data2", data2); QString optionStr = QJsonDocument(seriesData).toJson(); QString js = QString("init2(%1)").arg(optionStr); ui->widget->page()->runJavaScript(js); }然后运行程序,点击刚添加的Button就可以加载出数据了。
三、控制ECharts的大小
我们可以从HTML代码中可以看到,它定义了一个id为main的元素,并设置了style属性width,和height。
<div id="main" style="width: 750px;height:450px;"></div>并在js里用这个"main"初始化echarts实例,
// 基于准备好的dom,初始化echarts实例 var myChart = echarts.init(document.getElementById('main'));所以EChart的大小为750*450px,那么你们肯定会想,我们将<div>标签中的style的width和height设置为自动不就可以了吗?
<div id="main" style="width: 100%;height:100%;"></div>或者
<div id="main" style="width: auto;height:auto;"></div>开始我也是这么想的,可是通过试验这个行不通,QT在运行页面时会报错,并且也达不到预想的效果,只有设置为一个固定的*px时才能改变大小,所以我又将设置main标签的大小封装成了一个JS方法。代码如下。
function setSize(size){ // 首先是取到元素 var main = document.getElementById('main'); main.style.width = size["width"] + "px"; main.style.height = size["height"] + "px"; myChart.resize(); }同样也是通过JSON来传递数据,然后在QT中添加一个槽(SLOT)函数,代码如下:
void MainWindow::onResizeEcharts() { isLoaded = true; QJsonObject sizeData; sizeData.insert("width", ui->widget->width() - 20); sizeData.insert("height", ui->widget->height() - 20); QString sizeStr = QJsonDocument(sizeData).toJson(); QString js = QString("setSize(%1)").arg(sizeStr); ui->widget->page()->runJavaScript(js); }可以看到,我是依据QWebEngineView的大小来设置EChart的大小的,其中的isLoaded是判断页面是否完成 加载的标志,因为我们实现在窗口改变大小时ECharts也跟着变化,所以我们要在resizeEvent时设置也要设置大小,可是程序一运行它会执行一次,会导致还没加载完html页面它就执行了,然后报错,所以我加了一个标志来判断,因为QWebEngineView在load完一个页面后会发出一个已完成的信号,只有在load完成后我将这个标志设置为true就不会报错了。具体代码如下。
在.h文件中添加resizeEvent方法和isLoaded标志
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QtWebEngineWidgets/QWebEngineView> #include <QResizeEvent> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void on_test_clicked(); void on_test2_clicked(); void onResizeEcharts(); protected: virtual void resizeEvent(QResizeEvent *event) override; private: Ui::MainWindow *ui; bool isLoaded; }; #endif // MAINWINDOW_H在.cpp中添加
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); isLoaded = false; ui->widget->setContextMenuPolicy(Qt::NoContextMenu); ui->widget->load(QUrl("E:/workspace/QT_PRJ/echartsTest/htmlEcharts/testEcharts.html")); connect(ui->widget, SIGNAL(loadFinished(bool)), this, SLOT(onResizeEcharts())); } void MainWindow::resizeEvent(QResizeEvent *event) { if(isLoaded) onResizeEcharts(); }然后运行程序就可以动态的改变ECharts的大小了。
时间有点赶,写得有点粗糙。。。共同学习。