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 

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