QT5嵌入EChart进行数据可视化并保存图片

在之前的一篇博客《EChart配置方法(数据可视化解决方案)》已经很详细的介绍了 EChart,这篇我给大家介绍一下再Qt5中使用QChart进行数据可视化显示,并通过截图的方式保存显示图片。

1. 为何要嵌入Qt5中?

Qt作为一款广泛应用的图形化API在工程性和可移植性上做得非常好,其自身自带的QChart(QCart模块在Qt5中才开始配置到免费版本)也能做一部分的数据可视化,但相对于EChart来说简直是小巫见大巫了。(QChart应用示意如图1所示,ECahrt实例直接去官网看:https://www.echartsjs.com/examples/)而EChart作为JS库在跨平台上也毫不逊色于Qt,所以不用担心在其他平台的配置。将EChart嵌入到Qt5中可使项目更有工程性(画个图还要打开个网页或运行个黑框?)。

图1 QChart使用Demo

 2. Qt怎么结合EChart

Qt中有Web显示控件QWebEngineView,而EChart只作为一个本地网页载入到QWebEngineView中就行。

3. Qt怎么调用EChart中方法

Qt的QWebEngineView中有QWebEngineView->page()->runJavaScript(“function(data)”)对Js函数进行调用。 

 数据可以用Json格式传参方式到data中。(Json处理Qt中有QJsonObject等处理类)

4. 为什么要用截图方式保存

EChart在网页显示上其实是有图像保存按钮的,但是它是以下载方式将图片进行保存的,而Qt5中响应网页中的下载Url需要用到WebChannel(反正比截图麻烦)。

5. 实现步骤

5.1编写Html文件

方法和配置项都已经解释得非常清楚了这里就不再赘述了。直接上代码:(如果你直接复制记得将src=""改为自己的库路径)

EChartTest.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>ECharts</title>
    <!-- 引入 echarts.js -->
    <script src="D:/MYC/echarts4.2.1/incubator-echarts-4.2.1/dist/echarts.min.js"></script>
</head>
<body>
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('main'));

        // 指定图表的配置项和数据
        var option = {
            title: {
                text: 'ECharts 入门示例'
            },
            tooltip: {},
            legend: {
                data:['销量']
            },
            xAxis: {
                data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
            },
            yAxis: {},
            series: [{
                name: '销量',
                type: 'bar',
                data: [5, 20, 36, 10, 10, 20]
            }]
        };
		//折线图配置数据
		var optionLine={
			title:{
				text:'折线图示意图'
			},
            tooltip: {},
			legend:{data:['数据']},
			xAxis:{data:[]},
			yAxis:{},
			series:[{
				name:'数据',
				type:'line',
				data:[]}]
		};
		//曲线图配置数据
		var optionCurv={
			title:{
				text:'折线图示意图'
			},
			tooltip:{},
			legend:{data:['数据']},
			xAxis:{data:[]},
			yAxis:{},
			series:[{
				name:'数据',
				type:'line',
				smooth: true,
				data:[]}]
		};
		//柱状图配置数据
		var optionBar={
			title:{
				text:'折线图示意图'
			},
			tooltip:{},
			legend:{data:['数据']},
			xAxis:{data:[]},
			yAxis:{},
			series:[{
				name:'数据',
				type:'bar',
				data:[]}]
		};
		
        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption(option);
		
		/******************************************************
		*函数名:折线图
		*功  能:解析传入Json数据并传入至表格
		*输  入:srcData:传入Json数据
		*输  出:无
		******************************************************/
		function lineChart(srcData)
		{
			myChart.clear();						//显示清空
			var obj = JSON.parse(srcData); 			//将传入字符串转为标准Json格式
			if (obj.lineData.length < 1)			//如果传入数据长度为0
				return;
			optionLine.series[0].data=obj.lineData;	//将传入数据赋值给显示的数列
			for(var i=0;i<obj.lineData.length;i++)	//将X轴设置为0-lineData.lenth
			{
				optionLine.xAxis.data[i]=i;
			}
			myChart.setOption(optionLine);			//设置需要显示的配置项
		};
		
		/******************************************************
		*函数名:曲线图
		*功  能:解析传入Json数据并传入至表格
		*输  入:srcData:传入Json数据
		*输  出:无
		******************************************************/
		function curvChart(srcData)
		{
			myChart.clear();						//清空显示
			var obj = JSON.parse(srcData); 			//将传入字符串转为标准Json格式
			if (obj.lineData.length < 1)			//如果传入数据长度为0
				return;
			optionCurv.series[0].data=obj.lineData;	//将传入数据赋值给显示的数列
			for(var i=0;i<obj.lineData.length;i++)	//将X轴设置为0-lineData.lenth
			{
				optionCurv.xAxis.data[i]=i;
			}
			myChart.setOption(optionCurv);
		};
				
		/******************************************************
		*函数名:柱状图
		*功  能:解析传入Json数据并传入至表格
		*输  入:srcData:传入Json数据
		*输  出:无
		******************************************************/
		function barChart(srcData)
		{
			myChart.clear();						//清空显示
			var obj = JSON.parse(srcData); 			//将传入字符串转为标准Json格式
			if (obj.lineData.length < 1)			//如果传入数据长度为0
				return;
			optionBar.series[0].data=obj.lineData;	//将传入数据赋值给显示的数列
			for(var i=0;i<obj.lineData.length;i++)	//将X轴设置为0-lineData.lenth
			{
				optionBar.xAxis.data[i]=i;
			}
			myChart.setOption(optionBar);
		};
    </script>
</body>
</html>

5.2构建框架

   如图2所示,这个Demo有导入TXT文件、显示折线图、曲线图、柱状图、保存图像、设置保存路径功能。

图2 框架

 5.3构建代码框架并编写(直接上代码了)

EchartInQt5.h

#pragma once

#include <QtWidgets/QMainWindow>
#include "ui_EchartInQt5.h"
#include <qdebug.h>
#include <qwebengineview.h>
#include <qfile.h>
#include <qfiledialog.h>
#include <qjsonarray.h>
#include <qjsonobject.h>
#include <qjsondocument.h>
class EchartInQt5 : public QMainWindow
{
	Q_OBJECT

public:
	EchartInQt5(QWidget *parent = Q_NULLPTR);
	public slots:
	void on_inputDataBtn_clicked();			//导入数据槽函数
	void on_lineChartBtn_clicked();			//折线图显示槽函数
	void on_curvChartBtn_clicked();			//曲线图显示槽函数
	void on_barChartBtn_clicked();			//柱状图显示槽函数
	void on_saveImgBtn_clicked();			//保存图片槽函数
	void on_browseBtn_clicked();			//设置图片保存路径槽函数
private:
	Ui::EchartInQt5Class ui;
	QWebEngineView *pEngView;			//Web显示引擎
	QJsonArray dataLine;				//传入Json数据
	QString	saveImgName;				//图片保存名称
};

EchartInQt5.cpp

#include "EchartInQt5.h"

EchartInQt5::EchartInQt5(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);
	QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);                                    //设置应用程序用高分辨率显示
	this->setWindowTitle(QString::fromLocal8Bit("Qt5中用EChart进行数据可视化Demo"));               
 //设置应用标题
	pEngView = new QWebEngineView();                                                                //创建QWebEngineView实例
	ui.webLayout->addWidget(pEngView);                                                              //将QWebEngineView加入到Layout中
	pEngView->load(QUrl(QString::fromLocal8Bit("E:/C++/EchartInQt5/Win32/Debug/EChartTest.html"))); //载入EChart测试网页
	pEngView->show();                                                                               //显示网页
	ui.pathLEdt->setText(QCoreApplication::applicationDirPath());                                   //设置保存位置为项目所在位置
	ui.lineChartBtn->setDisabled(true);                                                             //设置折线图按钮不可按
	ui.curvChartBtn->setDisabled(true);                                                             //设置曲线图按钮不可按
	ui.barChartBtn->setDisabled(true);                                                              //设置柱状图按钮不可按

}
/****************************************************
*函数名:导入数据槽函数
*功  能:将稳步数据导入内存
*输  入:无
*输  出:无
*****************************************************/
void EchartInQt5::on_inputDataBtn_clicked()
{
	//打开文件
	ui.lagLab->clear();             //清空日志输出显示栏
	QString     path = QFileDialog::getOpenFileName(this, "Open File", "", "TXT File(*.txt)");
	QFile       textData(path);     //数据文件
	QString     lineStr;            //读取行
	QStringList dataTemp;           //临时数据
	if (!textData.open(QIODevice::ReadOnly))
	{
		ui.lagLab->setText(QString::fromLocal8Bit("导入文件失败!"));
		return;
	}
	while (!textData.atEnd())
	{
		lineStr = textData.readLine();                  //按行读取数据
		dataTemp = lineStr.split(' ', QString::SplitBehavior::SkipEmptyParts);
		if (dataTemp.count() > 0)
		{
			dataLine.append(dataTemp.at(0).toFloat());  //将读取到的数据转为float加入到Json中
		}
	}
	textData.close();                                   //关闭文件
	ui.lineChartBtn->setDisabled(false);																//设置折线图按钮可按
	ui.curvChartBtn->setDisabled(false);																//设置曲线图按钮可按
	ui.barChartBtn->setDisabled(false);																	//设置柱状图按钮可按
	ui.lagLab->setText(QString::fromLocal8Bit("导入文件成功!"));

}


/****************************************************
*函数名:折线图显示槽函数
*功  能:将数据以Json格式传入JS函数并显示折线图
*输  入:无
*输  出:无
*****************************************************/
void EchartInQt5::on_lineChartBtn_clicked()
{
	ui.lagLab->clear();                                             //清空日志输出显示栏
	QJsonObject jsonObject;                                         //构建用于传输数据的json对象
	saveImgName = QString::fromLocal8Bit("折线图");                 //设置保存图片名称
	jsonObject.insert("lineData", dataLine);                        //传入读取数据
	QString str = QString(QJsonDocument(jsonObject).toJson());      //将Json格式转为QString
	str = str.remove("\t").remove('\n');                            //移除多余的制表和换行
	str.replace(QRegExp("\""), "\\\"");                             //因为转为字符串后需要两次转译
	QString strVal = QString("lineChart(\"%1\");").arg(str);        //转为标准字符串
	pEngView->page()->runJavaScript(strVal);                        //调用js中的函数
	pEngView->show();                                               //显示网页
}


/****************************************************
*函数名:曲线图显示槽函数
*功  能:将数据以Json格式传入JS函数并显示曲线图
*输  入:无
*输  出:无
*****************************************************/
void EchartInQt5::on_curvChartBtn_clicked()
{
	ui.lagLab->clear();                                             //清空日志输出显示栏
	QJsonObject jsonObject;                                         //构建用于传输数据的json对象
	saveImgName = QString::fromLocal8Bit("曲线图");                 //设置保存图片名称
	jsonObject.insert("lineData", dataLine);                        //传入读取数据
	QString str = QString(QJsonDocument(jsonObject).toJson());      //将Json格式转为QString
	str = str.remove("\t").remove('\n');                            //移除多余的制表和换行
	str.replace(QRegExp("\""), "\\\"");	                            //因为转为字符串后需要两次转译
	QString strVal = QString("curvChart(\"%1\");").arg(str);        //转为标准字符串
	pEngView->page()->runJavaScript(strVal);                        //调用js中的函数
	pEngView->show();                                               //显示网页
}


/****************************************************
*函数名:柱状图显示槽函数
*功  能:将数据以Json格式传入JS函数并显示柱状图
*输  入:无
*输  出:无
*****************************************************/
void EchartInQt5::on_barChartBtn_clicked()
{
	ui.lagLab->clear();                                             //清空日志输出显示栏
	QJsonObject jsonObject;                                         //构建用于传输数据的json对象
	saveImgName = QString::fromLocal8Bit("柱状图");                 //设置保存图片名称
	jsonObject.insert("lineData", dataLine);                        //传入读取数据
	QString str = QString(QJsonDocument(jsonObject).toJson());      //将Json格式转为QString
	str = str.remove("\t").remove('\n');                            //移除多余的制表和换行
	str.replace(QRegExp("\""), "\\\"");                             //因为转为字符串后需要两次转译
	QString strVal = QString("barChart(\"%1\");").arg(str);         //转为标准字符串
	pEngView->page()->runJavaScript(strVal);                        //调用js中的函数
	pEngView->show();                                               //显示网页
}


/****************************************************
*函数名:保存图片槽函数
*功  能:以截图方式保存图片
*输  入:无
*输  出:无
*****************************************************/
void EchartInQt5::on_saveImgBtn_clicked()
{
	ui.lagLab->clear();
	QPixmap p = this->grab(QRect(30, 70, 661, 441));                //设置为Web显示位置geometry位置对于Layout并不好用哪位网友发现了解决方法请在下方评论中给出
	saveImgName = ui.pathLEdt->text() + "/" + saveImgName + ".png"; //设置保存位置
	QFile file(saveImgName);                                        //如果存在文件则删除原有文件
	if (file.exists())
		file.remove();
	file.close();	
	if (p.save(saveImgName, "png"))                                 //保存截图
	{
		ui.lagLab->setText(QString::fromLocal8Bit("保存成功!"));
	}
	else
	{
		ui.lagLab->setText(QString::fromLocal8Bit("保存失败!"));
	}
}


/****************************************************
*函数名:浏览文件夹槽函数
*功  能:选择保存图片的位置(默认路径为工程路径)
*输  入:无
*输  出:无
*****************************************************/
void EchartInQt5::on_browseBtn_clicked()
{
	QString path = QFileDialog::getExistingDirectory(this, QString::fromLocal8Bit("选择保存路径"), "/");
	if (path != NULL)
	{
		ui.pathLEdt->setText(path);
	}
}

测试数据.txt

12.5
13.6
11.2
10.5
8.3
7.2
9.5
10.6
11.2
12.6
14.6
12.3
11.2
15.6
11.3
10.2
16.5
15.3
16.3
17.5
19.5

显示结果:

 

工程下载地址:https://github.com/HuangYudong/EChartInQt5 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章