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的大小了。
时间有点赶,写得有点粗糙。。。共同学习。