QT5.5或QT5.6與echarts實現動態圖表
1.前言
ECharts開源來自百度商業前端資料視覺化團隊,基於html5 Canvas,是一個純Javascript圖表庫,提供直觀,生動,可互動,可個性化定製的資料視覺化圖表。創新的拖拽重計算、資料檢視、值域漫遊等特性大大增強了使用者體驗,賦予了使用者對資料進行挖掘、整合的能力。
在之前的blog中曾經就QT與echarts混合開發實現漂亮的圖表做了講解,參見《QT5中使用Echarts圖表元件》--連結地址:http://blog.csdn.net/liuyez123/article/details/50372123,但是QT與echarts混合開發還能打造豐富的動態圖表,例如:需要將分佈在全國各地的系統使用者數量統計出來,以地圖的形式展示出每個地域的使用者數量,使用者點選全國地圖中的各個省區域時,能夠開啟各省地圖,在各省地圖上的地市區域上以不同的顏色著色,顯示地域的使用者量情況。這個需求可以基於Echarts的地圖圖表功能實現,這是其他圖表工具很難做到的。先展示下最終實現效果。
2.實現思路
本例中右側的圖表是基於Echarts將分佈在全國各地的系統使用者數量統計出來,以地圖的形式展示出每個地域的使用者數量,使用者點選全國地圖中的各個省區域時,能夠開啟各省地圖,在各省地圖上的地市區域上以不同的顏色著色,顯示地域的使用者量情況,當滑鼠移到相應的地市上面還會顯示相應的資料。Echarts圖表還有更多複雜的功能大家可以參考百度Echarts的官方文件。
為了簡化演示程式,將使用者資料存放在檔案中,使用者資料以JSON格式存放。實際應用中可以將資料存放於資料庫。在本例中使用兩個JSON檔案,一個用於存放省和地市的對應資料,另一個用於存放各個地市的實際使用者資料。
在QtWebengine載入的Echarts圖表頁面中將點選選中的省份通過QtWebchannel傳至QT C++程式中,QT C++程式通過查詢存在JSON檔案中的資料,組成JSON格式的資料傳回Echart元件實現資料展現。QtWebchannel能夠實現QT C++和HTML頁中JS雙向資料互動,實現物件傳遞和基於QT的訊號和槽機制,具體的實現機制可以參看另一篇blog《
這種設計思路是基於:Echarts有著豐富的圖表展現功能,各種圖表的樣式是很容易在HTML和JS定製,而重要的資料來源(如圖中的各區域的使用者數量)是需要進行庫表的查詢、業務邏輯處理,最終進行展現資料的拼裝,這些處理工作不是Echarts的強項,但是QT卻很容易實現,所以可以將兩者結合進行混合開發,打造完美的應用。另外,Echarts是一款開源元件,可以流暢的執行在 PC 和移動裝置上,具有很強的跨平臺能力。
3.實現程式碼
Document物件是橋接QT C++
document.h內容
#ifndefDOCUMENT_H
#defineDOCUMENT_H
#include<QObject>
#include<QString>
#include<QJsonArray>
#include<QJsonObject>
classDocument:publicQObject
{
Q_OBJECT
Q_PROPERTY(QStringtextMEMBERs_textNOTIFYsendText)
public:
explicitDocument(QObject*parent=nullptr);
voidsetSendTextText(constQString&text);
publicslots:
voidreceiveText(constQString&r_text);
signals:
voidsendText(constQByteArray&text);
private:
QJsonObjectprovinceJsonObj;
QJsonArraycityJsonData;
QStrings_text;
QStringrecieve_text;
};
#endif//DOCUMENT_H
document.cpp內容
#include"document.h"
#include<QDebug>
#include<QJsonArray>
#include<QtCore/QFile>
#include<QtCore/QTextStream>
#include<QJsonDocument>
Document::Document(QObject*parent):QObject(parent)
{
QFileproJsonFile(":/provinces.json");
if(!proJsonFile.open(QIODevice::ReadOnly)){
qWarning("Couldn'topenproincesjsonfile.");
return;
}
QTextStreaminProData(&proJsonFile);
//將文字流讀取到字串中:
QStringprovinceDat=inProData.readAll();
//關閉文字流:
proJsonFile.close();
QJsonDocumentloadDoc(QJsonDocument::fromJson(provinceDat.toUtf8()));
provinceJsonObj=loadDoc.object();
QFilecityJsonFile(":/citygeo.json");
cityJsonFile.open(QIODevice::ReadOnly);
QTextStreaminData(&cityJsonFile);
//將文字流讀取到字串中:
QStringdat=inData.readAll();
//關閉文字流:
cityJsonFile.close();
QJsonDocumentdoc=QJsonDocument::fromJson(dat.toUtf8());
cityJsonData=doc.array();
}
voidDocument::setSendTextText(constQString&text)
{
QJsonArraycityArray=provinceJsonObj[text.toUtf8()].toArray();
QJsonArrayreturnArray;
for(intcityIndex=0;cityIndex<cityArray.size();++cityIndex)
{
QStringcity=cityArray[cityIndex].toString();
for(intvalueIndex=0;valueIndex<cityJsonData.size();++valueIndex)
{
QJsonObjectvalueObject=cityJsonData[valueIndex].toObject();
if(valueObject["name"].toString()==city)
{
returnArray.append(valueObject);
}
}
}
QJsonDocumentreturnDoc;
returnDoc.setArray(returnArray);
emitsendText(returnDoc.toJson());
}
/*!
ThisslotisinvokedfromtheHTMLclientsideandthetextdisplayedontheserverside.
*/
voidDocument::receiveText(constQString&r_text)
{
setSendTextText(r_text);
}
MainWidget物件負責主介面的顯示。
mainwidget.h內容
#ifndefMAINWIDGET_H
#defineMAINWIDGET_H
#include"document.h"
#include<QWidget>
#include<QString>
namespaceUi{
classMainWidget;
}
classMainWidget:publicQWidget
{
Q_OBJECT
public:
explicitMainWidget(QWidget*parent=0);
~MainWidget();
private:
Ui::MainWidget*ui;
Documentm_content;
};
#endif//MAINWIDGET_H
mainwidget.cpp內容
#include"mainwidget.h"
#include"ui_mainwidget.h"
#include"previewpage.h"
#include"document.h"
#include<QFile>
#include<QWebChannel>
MainWidget::MainWidget(QWidget*parent):
QWidget(parent),
ui(newUi::MainWidget)
{
ui->setupUi(this);
PreviewPage*page=newPreviewPage(this);
ui->preview->setPage(page);
QWebChannel*channel=newQWebChannel(this);
channel->registerObject(QStringLiteral("content"),&m_content);
page->setWebChannel(channel);
ui->preview->setUrl(QUrl("qrc:/index.html"));
}
MainWidget::~MainWidget()
{
deleteui;
}
previewpage.h內容
PreviewPage物件用於封裝展現Echarts元件的HTML頁面。
#ifndefPREVIEWPAGE_H
#definePREVIEWPAGE_H
#include<QWebEnginePage>
classPreviewPage:publicQWebEnginePage
{
Q_OBJECT
public:
explicitPreviewPage(QObject*parent=nullptr):QWebEnginePage(parent){}
protected:
boolacceptNavigationRequest(constQUrl&url,NavigationTypetype,boolisMainFrame);
};
#endif//PREVIEWPAGE_H
previewpage.cpp內容
#include"previewpage.h"
#include<QDesktopServices>
boolPreviewPage::acceptNavigationRequest(constQUrl&url,
QWebEnginePage::NavigationType/*type*/,
bool/*isMainFrame*/)
{
//Onlyallowqrc:/index.html.
if(url.scheme()==QString("qrc"))
returntrue;
QDesktopServices::openUrl(url);
returnfalse;
}
main.cpp內容
#include"document.h"
#include"mainwidget.h"
#include<QApplication>
intmain(intargc,char*argv[])
{
QApplicationa(argc,argv);
MainWidgetw;
w.show();
returna.exec();
}
注:例子中的provinces.json檔案只包含了部分省份的省名和組成地市對照關係,執行例子時,有正確對應關係的省份會以不同著色顯示,沒有的省份則顯示為灰色,但在編造的地市資料檔案citygeo.json檔案中除了上海、天津、北京三個直轄市外基本資料是完整的,如果感興趣可以自行新增資料補充完整。如有不明白之處可以給我留言~