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的地图图表功能实现,这是其他图表工具很难做到的。先展示下最终实现效果。

QT5.5或QT5.6与echarts实现动态图表_第1张图片

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的对象,QTDocument对象receiveText槽函数开放给JS,当HTML页面中用户点击相应的省份时调用此方法接收选中的省份,并最终发送sendText(constQByteArray&text)信号给JS通知HTML页面接受返回的处理结果。

 

document.h内容

 

#ifndefDOCUMENT_H

#defineDOCUMENT_H

 

#include

#include

#include

#include

 

 

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
#include
#include
#include
#include
 
 
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

#include

 

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
#include
 
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
 
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

 

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

 

intmain(intargc,char*argv[])

{

    QApplicationa(argc,argv);

    MainWidgetw;

    w.show();

 

    returna.exec();

}

 

文中使用例子的代码可以从此链接下载:http://download.csdn.net/detail/liuyez123/9407361

注:例子中的provinces.json文件只包含了部分省份的省名和组成地市对照关系,运行例子时,有正确对应关系的省份会以不同着色显示,没有的省份则显示为灰色,但在编造的地市数据文件citygeo.json文件中除了上海、天津、北京三个直辖市外基本数据是完整的,如果感兴趣可以自行添加数据补充完整。如有不明白之处可以给我留言~

你可能感兴趣的:(移动开发,C++,GUI编程)