天天看點

QT5.5或QT5.6與echarts實作動态圖表1.前言2.實作思路3.實作代碼

1.前言

ECharts開源來自百度商業前端資料可視化團隊,基于html5 Canvas,是一個純Javascript圖表庫,提供直覺,生動,可互動,可個性化定制的資料可視化圖表。創新的拖拽重計算、資料視圖、值域漫遊等特性大大增強了使用者體驗,賦予了使用者對資料進行挖掘、整合的能力。

在之前的blog中曾經就QT與echarts混合開發實作漂亮的圖表做了講解,參見《QT5中使用Echarts圖表元件》--連結位址:http://blog.csdn.net/liuyez123/article/details/50372123,但是QT與echarts混合開發還能打造豐富的動态圖表,例如:需要将分布在全國各地的系統使用者數量統計出來,以地圖的形式展示出每個地域的使用者數量,使用者點選全國地圖中的各個省區域時,能夠打開各省地圖,在各省地圖上的地市區域上以不同的顔色着色,顯示地域的使用者量情況。這個需求可以基于Echarts的地圖圖表功能實作,這是其他圖表工具很難做到的。先展示下最終實作效果。

QT5.5或QT5.6與echarts實作動态圖表1.前言2.實作思路3.實作代碼

2.實作思路

本例中右側的圖表是基于Echarts将分布在全國各地的系統使用者數量統計出來,以地圖的形式展示出每個地域的使用者數量,使用者點選全國地圖中的各個省區域時,能夠打開各省地圖,在各省地圖上的地市區域上以不同的顔色着色,顯示地域的使用者量情況,當滑鼠移到相應的地市上面還會顯示相應的資料。Echarts圖表還有更多複雜的功能大家可以參考百度Echarts的官方文檔。

為了簡化示範程式,将使用者資料存放在檔案中,使用者資料以JSON格式存放。實際應用中可以将資料存放于資料庫。在本例中使用兩個JSON檔案,一個用于存放省和地市的對應資料,另一個用于存放各個地市的實際使用者資料。

在QtWebengine載入的Echarts圖表頁面中将點選選中的省份通過QtWebchannel傳至QT C++程式中,QT C++程式通過查找存在JSON檔案中的資料,組成JSON格式的資料傳回Echart元件實作資料展現。QtWebchannel能夠實作QT C++和HTML頁中JS雙向資料互動,實作對象傳遞和基于QT的信号和槽機制,具體的實作機制可以參看另一篇blog《實作QT與HTML頁面通信》—連結位址:http://blog.csdn.net/liuyez123/article/details/50509788。

這種設計思路是基于:Echarts有着豐富的圖表展現功能,各種圖表的樣式是很容易在HTML和JS定制,而重要的資料源(如圖中的各區域的使用者數量)是需要進行庫表的查詢、業務邏輯處理,最終進行展現資料的拼裝,這些處理工作不是Echarts的強項,但是QT卻很容易實作,是以可以将兩者結合進行混合開發,打造完美的應用。另外,Echarts是一款開源元件,可以流暢的運作在 PC 和移動裝置上,具有很強的跨平台能力。

3.實作代碼

Document對象是橋接QT C++和JS的對象,QT将Document對象receiveText槽函數開放給JS,當HTML頁面中使用者點選相應的省份時調用此方法接收選中的省份,并最終發送sendText(constQByteArray&text)信号給JS通知HTML頁面接受傳回的處理結果。

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,

                                          bool)

{

    //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();

}

文中使用例子的代碼可以從此連結下載下傳:http://download.csdn.net/detail/liuyez123/9407361

注:例子中的provinces.json檔案隻包含了部分省份的省名群組成地市對照關系,運作例子時,有正确對應關系的省份會以不同着色顯示,沒有的省份則顯示為灰色,但在編造的地市資料檔案citygeo.json檔案中除了上海、天津、北京三個直轄市外基本資料是完整的,如果感興趣可以自行添加資料補充完整。如有不明白之處可以給我留言~