• Qt+ECharts开发笔记(五):ECharts的动态排序柱状图介绍、基础使用和Qt封装Demo


    前言

      上一篇的demo使用隐藏js代码的方式,实现了一个饼图的基本交互方式,并预留了Qt模块对外的基础接口。
      本篇的demo实现了自动排序的柱状图,实现了一个自动排序柱状图的基本交互方式,即Qt调用js脚本操作html。
      本篇demo使用Qt定时器方式,实现数据定时刷新自增,并预留出了定时器间隔参数。
      像大数据网页常看的人口增长时间图,收入年度增长时间图等都是这一类。

     

    Demo演示

      请添加图片描述

     

    ECharts代码效果调试

      使用ECharts的在线调试器,先调试出大致预期的效果。

    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封装动态ECharts

    步骤一:静态html

      此系列的标准html文件,因为是标准的所以对文件名进行了调整,改为eChartWidget.html。

    html>
    <html>
      <head>
        <meta charset="utf-8" />
        <title>EChartstitle>
        <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文件内容
        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::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);
    }
    

    开始统计(使用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("停止统计");
        }else{
            if(_timerId != -1)
            {
                killTimer(_timerId);
                _timerId = -1;
            }
            ui->pushButton_start->setText("开始统计");
        }
    }
    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);
    }
    
     

    Demo源码

    BarAutoSortEChartWidget.h

    #ifndef BARAUTOSORTECHARTWIDGET_H
    #define BARAUTOSORTECHARTWIDGET_H
    
    #include 
    #include 
    #include 
    #include 
    
    namespace Ui {
    class BarAutoSortEChartWidget;
    }
    
    class BarAutoSortEChartWidget : public QWidget
    {
        Q_OBJECT
    
    public:
        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 
    #include 
    #include 
    
    // QtCreator在msvc下设置编码也或有一些乱码,直接一刀切,避免繁琐的设置
    //#define MSVC
    #ifdef MSVC
    #define QSTRING(s)  QString::fromLocal8Bit(s)
    #else
    #define QSTRING(s)  QString(s)
    #endif
    
    #include 
    #include 
    //#define LOG qDebug()<<__FILE__<<__LINE__
    //#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__
    //#define LOG qDebug()<<__FILE__<<__LINE__<
    //#define LOG qDebug()<<__FILE__<<__LINE__<
    #define LOG qDebug()<<__FILE__<<__LINE__<"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文件内容
        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("停止统计");
        }else{
            if(_timerId != -1)
            {
                killTimer(_timerId);
                _timerId = -1;
            }
            ui->pushButton_start->setText("开始统计");
        }
    }
    
    void BarAutoSortEChartWidget::on_pushButton_reset_clicked()
    {
        initJs();
    }
    
     

    工程模板v1.4.0

      在这里插入图片描述

     

    入坑

    入坑一:排序图问题无法自动排序

    问题

      没有排序:
      在这里插入图片描述

    原理

      这里之前我们已经遇见各种坑了,所以直接上调试工具,将Qt的js初始化代码在调试工具当中跑,如下图,web调试网页效果:
      在这里插入图片描述

    解决方法

      自己调整序号,交换数据可以实现,但是无法实现上下条交换的动画了。

  • 相关阅读:
    一文了解DataStore(Preferences)
    动态行、列,并且合并
    【Day32】LeetCode刷刷刷。[1700. 无法吃午餐的学生数量 ]
    刷题记录:NC15322强迫症的序列
    如果C盘满了怎么办
    4.6、在线调试工具 ILA 的使用
    element ui:常用的组件使用情况记录
    阿里云CDN是什么意思?
    [Database] 脏读、幻读这些都是什么?事务隔离级别又是什么?MySQL数据库的事务隔离级别都有哪些?
    【无标题】
  • 原文地址:https://www.cnblogs.com/qq21497936/p/16755404.html