Echarts是百度的可视化图表库(js),有各种漂亮的折线、饼、柱、雷达、散点图,之前做网页信息图表时就体会到它具有很强大的表达能力(不仅仅是展示数据,更重要的是表达信息),所以很想把它集成到QT中,代替目前手头已开发的软件中的qwt。
目标:
在QT实现的软件中嵌入Echarts折线图,折线图中的数据、标题等从qt部分传给Echarts的js部分。
实现:
1.在QT界面中使用QWebView来装载一个包含Echarts折线图的html页面。
2.QT向html传递数据时使用json格式字符串。
3.html和js文件作为QT RESOURCES打包编译,这样发布时只有一个可执行程序,没有额外的配置。
遗留问题:可能是操作系统的X11库有bug,我遭遇了下面这样的错误,有时在关闭界面时会coredump。
XIO: fatal IO error 11 (资源暂时不可用) on X server "愼U"
after 36191 requests (36190 known processed) with 0 events remaining.
使用到的开源软件如下,非常感谢前人的轮子!!!
Echarts实例
qt与echarts配合打造最强图表库 我的代码是在他的开源上的一些增加
cJSON 一个非常好用的C语言解析JSON的开源库
我的代码文件结构如下所示,res目录下是html和js文件,通过qrc文件指定资源,就可以将其静态打包到可执行程序中,cJSON是处理json结构对象和字符串的c库,widget是处理加载页面,传参到js的qt程序
部分源码在这里,写了一些注释。
main.cpp
#include "widget.h"
#include <QApplication>
#include <QTextCodec>
int main(int argc, char *argv[])
{
QTextCodec::setCodecForTr( QTextCodec::codecForName("utf8") );
QTextCodec::setCodecForCStrings( QTextCodec::codecForName("utf8") );
QTextCodec::setCodecForLocale( QTextCodec::codecForName("utf8") );
Q_INIT_RESOURCE(main);
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.cpp
#include <sys/time.h>
#include "widget.h"
#include "ui_widget.h"
#include "cJSON.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
ui->webView->load(QUrl("qrc:/res/curve.html")); //加载页面
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnLine_clicked()
{
// 创建一些随机数
float array[1440];
int max=1000, min=0;
struct timeval tv_rand;
for (int i=0; i<1440; i++)
{
gettimeofday(&tv_rand, (struct timezone*)0);
srand(tv_rand.tv_usec);
array[i] = (rand() % ((int)max*10000 - (int)min*10000))/10000.0 + min;
}
// 构建用于传输数据的json对象
cJSON *root;
char *out;
root=cJSON_CreateObject();
// json对象结构 {"title":"xxxxx", "value":[float array]}
cJSON_AddStringToObject(root, "title", "日负荷曲线"); // 有中文的需求要注意使用UTF-8编码
cJSON_AddItemToObject(root, "value", cJSON_CreateFloatArray(array, 1440));
out=cJSON_Print(root); // json对象转字符串
cJSON_Minify(out); // 去掉字符串中的换行和缩进
QString str = QString(out);
cJSON_Delete(root);
// 把json字符串中所有双引号前面再加上一个转义符
// 因为这个字符串到了js里面还要被parseJSON一次,所以\\不可少
str.replace(QRegExp("\""), "\\\"");
// callfromqt是js中的函数名 str是其入参
QString strVal = QString("callfromqt(\"%1\");").arg(str);
printf("strVal : %s \n", strVal.toStdString().c_str());
// 调用js中的函数
ui->webView->page()->mainFrame()->evaluateJavaScript(strVal);
}
curve.html
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>ECharts</title>
</head>
<body>
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="height:400px"></div>
<!-- 因为连js都会被打包到可执行程序中,所以这里引入echarts-all.js而不是require动态加载 -->
<script src="jquery.min.js"></script>
<script src="build/dist/echarts-all.js"></script>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts图表, macarons是echarts主题,换样式的,可略
var myChart = echarts.init(document.getElementById('main'),'macarons');
// 组织option
var option = {
title : {
text: '' //名字由qt传进来
},
tooltip:{
show : true,
trigger: 'axis', // 坐标轴触发 也可以item数据点触发
formatter:function (params){ // tip的样式
var res = '时间 : ' + params[0].name +'<br/>';
for (var i = 0, l = params.length; i < l; i++) {
res += '<br/>' + params[i].seriesName + ' : ' + params[i].value;
}
return res;
}
},
calculable : false,
xAxis : [
{
type : 'category',
boundaryGap : false,
axisLabel:{interval:0},
data : []
}
],
yAxis : [
{
type : 'value'
}
],
series : [
{
name:'今日',
type:'line',
data:[]
}
]
};
//窗体自适应
window.onresize = myChart.resize;
// 为echarts对象加载数据
function callfromqt(str)
{
var obj = $.parseJSON(str); // 可能我的QT版本有点低,webkit不能支持原生的JSON.parse
if (obj.value.length < 1)
return;
option.title.text=obj.title;
option.series[0].data = obj.value;
// 下面是根据传入的采样点数拼坐标轴 可略
option.xAxis[0].data = getDayXAsis(obj.value.length);
if ( option.xAxis[0].data.length > 12)
option.xAxis[0].axisLabel.interval = option.xAxis[0].data.length/12 -1;
else
option.xAxis[0].axisLabel.interval = 0;
// 画折线图
myChart.setOption(option);
}
// 根据数据点数创建日曲线的x轴标签
function getDayXAsis(split_num)
{
var xasis = [];
// 如果是288点就5分钟一个标签 96点就15分钟一个标签
var offset = 86400/split_num;
var d = new Date(1999, 1, 1);
for (var i=0; i<split_num; i++)
{
var nd = new Date();
nd.setTime(d.getTime() +offset*1000*i);
var str = compZero(nd.getHours(),2)+":"+compZero(nd.getMinutes(),2);
xasis.push(str);
}
return xasis;
}
// 左补0
function compZero(intn, bits)
{
var int_str = "" + intn;
if (int_str.length >= bits)
return int_str;
var comp_str = "";
var comp_len = bits - int_str.length;
for (var i=0; i<comp_len; i++)
comp_str += "0";
comp_str += int_str;
return comp_str;
}
</script>
</body>
小结:
QT向js传递参数中有中文的话,qt文件要存为UTF-8的格式,否则会造成乱码。
以json字符串传递参数是,要对引号再加一次转义符,否则在js中无法解析。
Echarts在网页上展示数据的性能号称20W数据秒级出图,但在QT中出图的动画效果有明显卡顿,但仍在可接受范围内。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。