Qt+ECharts開發(fā)筆記(五):ECharts的動態(tài)排序柱狀圖介紹、基礎使用和Qt封裝Demo
前言
??上一篇的demo使用隱藏js代碼的方式,實現(xiàn)了一個餅圖的基本交互方式,并預留了Qt模塊對外的基礎接口。
??本篇的demo實現(xiàn)了自動排序的柱狀圖,實現(xiàn)了一個自動排序柱狀圖的基本交互方式,即Qt調(diào)用js腳本操作html。
??本篇demo使用Qt定時器方式,實現(xiàn)數(shù)據(jù)定時刷新自增,并預留出了定時器間隔參數(shù)。
??像大數(shù)據(jù)網(wǎng)頁??吹娜丝谠鲩L時間圖,收入年度增長時間圖等都是這一類。
Demo演示
??

ECharts代碼效果調(diào)試
??使用ECharts的在線調(diào)試器,先調(diào)試出大致預期的效果。
option = {
?xAxis: {
? ?max: 'dataMax'
?},
?yAxis: {
? ?type: 'category',
? ?data: ['特斯拉', '奔馳', '寶馬', '理想', '蔚來'],
? ?inverse: true,
? ?animationDuration: 300,
? ?animationDurationUpdate: 300,
? ?max: 4
?},
?series: [
? ?{
? ? ?realtimeSort: true,
? ? ?name: 'X',
? ? ?type: 'bar',
? ? ?data: [10,20,50,10,30],
? ? ?label: {
? ? ? ?show: true,
? ? ? ?position: 'right',
? ? ? ?valueAnimation: true
? ? ?},
? ? ?itemStyle: {
? ? ? ? ? ?color: function(params) {
? ? ? ? ? ? ?var colorList = ['#EE14FF', '#F092FF', '#FF61FE', '#A02F99', '#F00682']; ?/* 注意1:需要分號 */
? ? ? ? ? ? ?return colorList[params.dataIndex]; ? ?/* 注意2:需要dataIndex,獲取序號 */
? ? ? ? }
? ? ?}
? ?},
?],
?graphic: {
? ?elements: [ ? ?/* 時間標志 */
? ? ?{
? ? ? ?type: 'text',
? ? ? ?right: 160,
? ? ? ?bottom: 100,
? ? ? ?style: {
? ? ? ? ?text: '1970-01',
? ? ? ? ?font: 'bolder 100px monospace',
? ? ? ? ?fill: 'rgba(100, 100, 100, 0.25)'
? ? ? ?},
? ? ? ?z: 100
? ? ?}
? ?]
?},
?legend: {
? ?show: false,
?},
?animationDuration: 0,
?animationDurationUpdate: 1000,
?animationEasing: 'linear',
?animationEasingUpdate: 'linear'};
??

Qt封裝動態(tài)ECharts
步驟一:靜態(tài)html
??此系列的標準html文件,因為是標準的所以對文件名進行了調(diào)整,改為eChartWidget.html。
<!DOCTYPE html><html>
?<head>
? ?<meta charset="utf-8" />
? ?<title>ECharts</title>
? ?<script src="./echarts.js"></script>
?</head>
?<body>
? ?<style>
? ? ? ?#main,
? ? ? ?html,
? ? ? ?body{
? ? ? ? ? ?width: 100%;
? ? ? ? ? ?height: 100%;
? ? ? ? ? ?overflow: hidden;
? ? ? ?}
? ? ? ?#main {
? ? ? ? ? ?width: 95%;
? ? ? ? ? ?height: 95%;
? ? ? ?}
? ?</style>
? ?<div id="main"></div>
? ?<script type="text/javascript">
? ? ? ?var myChart = echarts.init(document.getElementById('main'));
? ? ? ?window.onresize = function() {
? ? ? ? ? ?myChart.resize();
? ? ? ?};
? ?</script>
?</body></html>
步驟二:初始化
void BarAutoSortEChartWidget::initControl(){
? ?_pWebEngineView = new QWebEngineView(this);
? ?_pWebEnginePage = new QWebEnginePage(this);
? ?_pWebChannel = new QWebChannel(this);
? ?QString filePath;#if 1
? ?filePath = QString("%1/%2").arg(_htmlDir).arg(_indexFileName);#else
? ?filePath = "qrc:/barAutoSortEChartWidget/html/eChartWidget.html";#endif
? ?LOG << "file exist:" << QFile::exists(filePath) << filePath;#if 0
? ?// 打印html文件內(nèi)容
? ?QFile file(_indexFilePath);
? ?file.open(QIODevice::ReadOnly);
? ?LOG << QString(file.readAll());
? ?file.close();#endif
? ?connect(_pWebEnginePage, SIGNAL(loadFinished(bool)), this, SLOT(slot_loadFinished(bool)));
? ?_pWebEnginePage->load(QUrl(filePath));
? ?_pWebEnginePage->setWebChannel(_pWebChannel);
? ?_pWebEngineView->setPage(_pWebEnginePage);
? ?// 背景透明// ? ?_pWebEngineView->setStyleSheet("background-color: transparent");
? ?_pWebEnginePage->setBackgroundColor(Qt::transparent);}
步驟三:動態(tài)操作
??

重置
void BarAutoSortEChartWidget::on_pushButton_reset_clicked(){
? ?initJs();}
刷新
void BarAutoSortEChartWidget::on_pushButton_flush_clicked(){
? ?QString jsStr =
? ? ? ? ? ?"var empty = {};"
? ? ? ? ? ?"myChart.setOption(empty, true);"
? ? ? ? ? ?"myChart.setOption(option, true);";
? ?runJsScript(jsStr);}
開始統(tǒng)計(使用Qt代碼)
??這里預留了定時器間隔。
void BarAutoSortEChartWidget::on_pushButton_start_clicked(){
? ?if(_timerId == -1)
? ?{
? ? ? ?LOG << ui->lineEdit_interval->text().toInt();
? ? ? ?_timerId = startTimer(ui->lineEdit_interval->text().toInt());
? ? ? ?_dateTime.setSecsSinceEpoch(0);
? ? ? ?QString jsStr = QString(
? ? ? ? ? ? ? ?"option.series[0].data[0] = 0;"
? ? ? ? ? ? ? ?"option.series[0].data[1] = 0;"
? ? ? ? ? ? ? ?"option.series[0].data[2] = 0;"
? ? ? ? ? ? ? ?"option.series[0].data[3] = 0;"
? ? ? ? ? ? ? ?"option.series[0].data[4] = 0;"
? ? ? ? ? ? ? ?"option.graphic.elements[0].style.text= '%1';"
? ? ? ? ? ? ? ?"myChart.setOption(option, true);"
? ? ? ? ? ? ? ?)
? ? ? ? ? ? ? ?.arg(_dateTime.toString("yyyy-MM"));
? ? ? ?runJsScript(jsStr);
? ? ? ?ui->pushButton_start->setText("停止統(tǒng)計");
? ?}else{
? ? ? ?if(_timerId != -1)
? ? ? ?{
? ? ? ? ? ?killTimer(_timerId);
? ? ? ? ? ?_timerId = -1;
? ? ? ?}
? ? ? ?ui->pushButton_start->setText("開始統(tǒng)計");
? ?}}void BarAutoSortEChartWidget::timerEvent(QTimerEvent *event){
? ?_dateTime = _dateTime.addMonths(1);
? ?if(_dateTime >= QDateTime::currentDateTime())
? ?{
? ? ? ?if(_timerId != -1)
? ? ? ?{
? ? ? ? ? ?killTimer(_timerId);
? ? ? ? ? ?_timerId = -1;
? ? ? ?}
? ?}
? ?QString jsStr = QString(
? ? ? ? ? ?"option.series[0].data[0] = option.series[0].data[0] + %1;"
? ? ? ? ? ?"option.series[0].data[1] = option.series[0].data[1] + %2;"
? ? ? ? ? ?"option.series[0].data[2] = option.series[0].data[2] + %3;"
? ? ? ? ? ?"option.series[0].data[3] = option.series[0].data[3] + %4;"
? ? ? ? ? ?"option.series[0].data[4] = option.series[0].data[4] + %5;"
? ? ? ? ? ?"option.graphic.elements[0].style.text= '%6';"
? ? ? ? ? ?"myChart.setOption(option, true);"
? ? ? ? ? ?)
? ? ? ? ? ?.arg(qrand()%100)
? ? ? ? ? ?.arg(qrand()%100)
? ? ? ? ? ?.arg(qrand()%100)
? ? ? ? ? ?.arg(qrand()%100)
? ? ? ? ? ?.arg(qrand()%100)
? ? ? ? ? ?.arg(_dateTime.toString("yyyy-MM"));
? ?runJsScript(jsStr);}
清除數(shù)據(jù)
void BarAutoSortEChartWidget::on_pushButton_clear_clicked(){
? ?_dateTime.setSecsSinceEpoch(0);
? ?QString jsStr = QString(
? ? ? ? ? ?"option.series[0].data[0] = 0;"
? ? ? ? ? ?"option.series[0].data[1] = 0;"
? ? ? ? ? ?"option.series[0].data[2] = 0;"
? ? ? ? ? ?"option.series[0].data[3] = 0;"
? ? ? ? ? ?"option.series[0].data[4] = 0;"
? ? ? ? ? ?"option.graphic.elements[0].style.text= '%1';"
? ? ? ? ? ?"myChart.setOption(option, true);"
? ? ? ? ? ?)
? ? ? ? ? ?.arg(_dateTime.toString("yyyy-MM"));
? ?runJsScript(jsStr);}
Demo源碼
BarAutoSortEChartWidget.h
#ifndef BARAUTOSORTECHARTWIDGET_H#define BARAUTOSORTECHARTWIDGET_H#include <QWidget>#include <QWebEngineView>#include <QWebEnginePage>#include <QWebChannel>namespace Ui {class BarAutoSortEChartWidget;}class BarAutoSortEChartWidget : public QWidget{
? ?Q_OBJECTpublic:
? ?explicit BarAutoSortEChartWidget(QWidget *parent = 0);
? ?~BarAutoSortEChartWidget();protected:
? ?void initControl();protected slots:
? ?void slot_loadFinished(bool result);protected:
? ?void initJs();protected:
? ?void runJsScript(QString str);protected:
? ?void resizeEvent(QResizeEvent *event);
? ?void timerEvent(QTimerEvent *event);private slots:
? ?void on_pushButton_clear_clicked();
? ?void on_pushButton_flush_clicked();
? ?void on_pushButton_start_clicked();
? ?void on_pushButton_reset_clicked();private:
? ?Ui::BarAutoSortEChartWidget *ui;private:
? ?QWebEngineView *_pWebEngineView; ? ? ? ? ? ?// 瀏覽器窗口
? ?QWebEnginePage *_pWebEnginePage; ? ? ? ? ? ?// 瀏覽器頁面
? ?QWebChannel *_pWebChannel; ? ? ? ? ? ? ? ? ?// 瀏覽器js交互
? ?QString _htmlDir; ? ? ? ? ? ? ? ? ? ? ? ? ? // html文件夾路徑
? ?QString _indexFileName; ? ? ? ? ? ? ? ? ? ? // html文件
? ?QString _initJsStr; ? ? ? ? ? ? ? ? ? ? ? ? // 第一次初始化的表格private:
? ?int _timerId;
? ?QDateTime _dateTime;};#endif // BARAUTOSORTECHARTWIDGET_H
BarAutoSortEChartWidget.cpp
#include "BarAutoSortEChartWidget.h"#include "ui_BarAutoSortEChartWidget.h"#include <QFile>#include <QMessageBox>#include <QTimer>// QtCreator在msvc下設置編碼也或有一些亂碼,直接一刀切,避免繁瑣的設置//#define MSVC#ifdef MSVC#define QSTRING(s) ?QString::fromLocal8Bit(s)#else#define QSTRING(s) ?QString(s)#endif#include <QDebug>#include <QDateTime>//#define LOG qDebug()<<__FILE__<<__LINE__//#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__//#define LOG qDebug()<<__FILE__<<__LINE__<<QThread()::currentThread()//#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd")#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")BarAutoSortEChartWidget::BarAutoSortEChartWidget(QWidget *parent) :
? ?QWidget(parent),
? ?ui(new Ui::BarAutoSortEChartWidget),
? ?_pWebEngineView(0),
? ?_pWebEnginePage(0),
? ?_pWebChannel(0),
? ?_htmlDir("D:/qtProject/echartsDemo/echartsDemo/modules/barAutoSortEChartWidget/html"), ? ?// 使用了絕對路徑,引到html文件夾
? ?_indexFileName("eChartWidget.html"),
? ?_timerId(-1){
? ?ui->setupUi(this);
? ?QString version = "v1.0.0";
? ?setWindowTitle(QString("基于Qt的ECharts條狀圖(自動排序)Demo %1(長沙紅胖子).arg(version));
? ?// 設置無邊框,以及背景透明
? ?// 背景透明,在界面構架時,若為本窗口為其他窗口提升為本窗口時,
? ?// 則再qss會在主窗口第一級添加frame_all,防止其他窗口提升本窗口而沖掉qss設置// ? ?setWindowFlag(Qt::FramelessWindowHint);// ? ?setAttribute(Qt::WA_TranslucentBackground, true);#if 0
? ?// 這是方法一:讓滾動條不出來(通過大小),還有一個方法是在html設置body的overflow: hidden// ? ?resize(600 + 20, 400 + 20);#endif
? ?initControl();}BarAutoSortEChartWidget::~BarAutoSortEChartWidget(){
? ?delete ui;}void BarAutoSortEChartWidget::initControl(){
? ?_pWebEngineView = new QWebEngineView(this);
? ?_pWebEnginePage = new QWebEnginePage(this);
? ?_pWebChannel = new QWebChannel(this);
? ?QString filePath;#if 1
? ?filePath = QString("%1/%2").arg(_htmlDir).arg(_indexFileName);#else
? ?filePath = "qrc:/barAutoSortEChartWidget/html/eChartWidget.html";#endif
? ?LOG << "file exist:" << QFile::exists(filePath) << filePath;#if 0
? ?// 打印html文件內(nèi)容
? ?QFile file(_indexFilePath);
? ?file.open(QIODevice::ReadOnly);
? ?LOG << QString(file.readAll());
? ?file.close();#endif
? ?connect(_pWebEnginePage, SIGNAL(loadFinished(bool)), this, SLOT(slot_loadFinished(bool)));
? ?_pWebEnginePage->load(QUrl(filePath));
? ?_pWebEnginePage->setWebChannel(_pWebChannel);
? ?_pWebEngineView->setPage(_pWebEnginePage);
? ?// 背景透明// ? ?_pWebEngineView->setStyleSheet("background-color: transparent");
? ?_pWebEnginePage->setBackgroundColor(Qt::transparent);}void BarAutoSortEChartWidget::slot_loadFinished(bool result){
? ?if(result)
? ?{
? ? ? ?initJs();
? ? ? ?// 因為使用布局,在沒有完全構造之前,其大小是不可預期的,等構造完成后,布局的大小才會形成,此時再初始化一次
? ? ? ?resizeEvent(0);
? ?}}void BarAutoSortEChartWidget::initJs(){
? ?_initJsStr = QSTRING(
? ? ? ? ? ?"option = {"
? ? ? ? ? ?" ?xAxis: {"
? ? ? ? ? ?" ? ?max: 'dataMax'"
? ? ? ? ? ?" ?},"
? ? ? ? ? ?" ?yAxis: {"
? ? ? ? ? ?" ? ?type: 'category',"
? ? ? ? ? ?" ? ?data: ['特斯拉', '奔馳', '寶馬', '理想', '蔚來'],"
? ? ? ? ? ?" ? ?inverse: true,"
? ? ? ? ? ?" ? ?animationDuration: 300,"
? ? ? ? ? ?" ? ?animationDurationUpdate: 300,"
? ? ? ? ? ?" ? ?max: 4"
? ? ? ? ? ?" ?},"
? ? ? ? ? ?" ?series: ["
? ? ? ? ? ?" ? ?{"
? ? ? ? ? ?" ? ? ?realtimeSort: true,"
? ? ? ? ? ?" ? ? ?name: 'X',"
? ? ? ? ? ?" ? ? ?type: 'bar',"
? ? ? ? ? ?" ? ? ?data: [10,20,50,10,30],"
? ? ? ? ? ?" ? ? ?label: {"
? ? ? ? ? ?" ? ? ? ?show: true,"
? ? ? ? ? ?" ? ? ? ?position: 'right',"
? ? ? ? ? ?" ? ? ? ?valueAnimation: true"
? ? ? ? ? ?" ? ? ?},"
? ? ? ? ? ?" ? ? ?itemStyle: {"
? ? ? ? ? ?" ? ? ? ? ? ?color: function(params) {"
? ? ? ? ? ?" ? ? ? ? ? ? ?var colorList = ['#EE14FF', '#F092FF', '#FF61FE', '#A02F99', '#F00682']; ?/* 注意1:需要分號 */"
? ? ? ? ? ?" ? ? ? ? ? ? ?return colorList[params.dataIndex]; ? ?/* 注意2:需要dataIndex,獲取序號 */"
? ? ? ? ? ?" ? ? ? ? }"
? ? ? ? ? ?" ? ? ?}"
? ? ? ? ? ?" ? ?},"
? ? ? ? ? ?" ?],"
? ? ? ? ? ?" ?graphic: {"
? ? ? ? ? ?" ? ?elements: [ ? ?/* 時間標志 */"
? ? ? ? ? ?" ? ? ?{"
? ? ? ? ? ?" ? ? ? ?type: 'text', "
? ? ? ? ? ?" ? ? ? ?right: 160,"
? ? ? ? ? ?" ? ? ? ?bottom: 100,"
? ? ? ? ? ?" ? ? ? ?style: {"
? ? ? ? ? ?" ? ? ? ? ?text: '1970-01',"
? ? ? ? ? ?" ? ? ? ? ?font: 'bolder 100px monospace',"
? ? ? ? ? ?" ? ? ? ? ?fill: 'rgba(100, 100, 100, 0.25)'"
? ? ? ? ? ?" ? ? ? ?},"
? ? ? ? ? ?" ? ? ? ?z: 100"
? ? ? ? ? ?" ? ? ?}"
? ? ? ? ? ?" ? ?]"
? ? ? ? ? ?" ?},"
? ? ? ? ? ?" ?legend: {"
? ? ? ? ? ?" ? ?show: false,"
? ? ? ? ? ?" ?},"
? ? ? ? ? ?" ?animationDuration: 0,"
? ? ? ? ? ?" ?animationDurationUpdate: 1000,"
? ? ? ? ? ?" ?animationEasing: 'linear',"
? ? ? ? ? ?" ?animationEasingUpdate: 'linear'"
? ? ? ? ? ?"};"
? ? ? ? ? ?"myChart.setOption(option);");
? ?runJsScript(_initJsStr);}void BarAutoSortEChartWidget::runJsScript(QString str){
? ?if(_pWebEnginePage)
? ?{
? ? ? ?_pWebEnginePage->runJavaScript(str);
? ?}}void BarAutoSortEChartWidget::resizeEvent(QResizeEvent *event){
? ?if(_pWebEngineView)
? ?{
? ? ? ?_pWebEngineView->setGeometry(ui->label_echarts->geometry());
? ? ? ?LOG << ui->label_echarts->geometry();
? ?}}void BarAutoSortEChartWidget::timerEvent(QTimerEvent *event){
? ?_dateTime = _dateTime.addMonths(1);
? ?if(_dateTime >= QDateTime::currentDateTime())
? ?{
? ? ? ?if(_timerId != -1)
? ? ? ?{
? ? ? ? ? ?killTimer(_timerId);
? ? ? ? ? ?_timerId = -1;
? ? ? ?}
? ?}
? ?QString jsStr = QString(
? ? ? ? ? ?"option.series[0].data[0] = option.series[0].data[0] + %1;"
? ? ? ? ? ?"option.series[0].data[1] = option.series[0].data[1] + %2;"
? ? ? ? ? ?"option.series[0].data[2] = option.series[0].data[2] + %3;"
? ? ? ? ? ?"option.series[0].data[3] = option.series[0].data[3] + %4;"
? ? ? ? ? ?"option.series[0].data[4] = option.series[0].data[4] + %5;"
? ? ? ? ? ?"option.graphic.elements[0].style.text= '%6';"
? ? ? ? ? ?"myChart.setOption(option, true);"
? ? ? ? ? ?)
? ? ? ? ? ?.arg(qrand()%100)
? ? ? ? ? ?.arg(qrand()%100)
? ? ? ? ? ?.arg(qrand()%100)
? ? ? ? ? ?.arg(qrand()%100)
? ? ? ? ? ?.arg(qrand()%100)
? ? ? ? ? ?.arg(_dateTime.toString("yyyy-MM"));
? ?runJsScript(jsStr);}void BarAutoSortEChartWidget::on_pushButton_clear_clicked(){
? ?_dateTime.setSecsSinceEpoch(0);
? ?QString jsStr = QString(
? ? ? ? ? ?"option.series[0].data[0] = 0;"
? ? ? ? ? ?"option.series[0].data[1] = 0;"
? ? ? ? ? ?"option.series[0].data[2] = 0;"
? ? ? ? ? ?"option.series[0].data[3] = 0;"
? ? ? ? ? ?"option.series[0].data[4] = 0;"
? ? ? ? ? ?"option.graphic.elements[0].style.text= '%1';"
? ? ? ? ? ?"myChart.setOption(option, true);"
? ? ? ? ? ?)
? ? ? ? ? ?.arg(_dateTime.toString("yyyy-MM"));
? ?runJsScript(jsStr);}void BarAutoSortEChartWidget::on_pushButton_flush_clicked(){
? ?QString jsStr =
? ? ? ? ? ?"var empty = {};"
? ? ? ? ? ?"myChart.setOption(empty, true);"
? ? ? ? ? ?"myChart.setOption(option, true);";
? ?runJsScript(jsStr);}void BarAutoSortEChartWidget::on_pushButton_start_clicked(){
? ?if(_timerId == -1)
? ?{
? ? ? ?LOG << ui->lineEdit_interval->text().toInt();
? ? ? ?_timerId = startTimer(ui->lineEdit_interval->text().toInt());
? ? ? ?_dateTime.setSecsSinceEpoch(0);
? ? ? ?QString jsStr = QString(
? ? ? ? ? ? ? ?"option.series[0].data[0] = 0;"
? ? ? ? ? ? ? ?"option.series[0].data[1] = 0;"
? ? ? ? ? ? ? ?"option.series[0].data[2] = 0;"
? ? ? ? ? ? ? ?"option.series[0].data[3] = 0;"
? ? ? ? ? ? ? ?"option.series[0].data[4] = 0;"
? ? ? ? ? ? ? ?"option.graphic.elements[0].style.text= '%1';"
? ? ? ? ? ? ? ?"myChart.setOption(option, true);"
? ? ? ? ? ? ? ?)
? ? ? ? ? ? ? ?.arg(_dateTime.toString("yyyy-MM"));
? ? ? ?runJsScript(jsStr);
? ? ? ?ui->pushButton_start->setText("停止統(tǒng)計");
? ?}else{
? ? ? ?if(_timerId != -1)
? ? ? ?{
? ? ? ? ? ?killTimer(_timerId);
? ? ? ? ? ?_timerId = -1;
? ? ? ?}
? ? ? ?ui->pushButton_start->setText("開始統(tǒng)計");
? ?}}void BarAutoSortEChartWidget::on_pushButton_reset_clicked(){
? ?initJs();}
工程模板v1.4.0
??

入坑
入坑一:排序圖問題無法自動排序
問題
??沒有排序:
??

原理
??這里之前我們已經(jīng)遇見各種坑了,所以直接上調(diào)試工具,將Qt的js初始化代碼在調(diào)試工具當中跑,如下圖,web調(diào)試網(wǎng)頁效果:
??

解決方法
??自己調(diào)整序號,交換數(shù)據(jù)可以實現(xiàn),但是無法實現(xiàn)上下條交換的動畫了。