前言

  上一篇成功是EChart随着Qt窗口变化而变化,本篇将开始正式介绍柱状图介绍、基础使用,并将其封装一层Qt。
  本篇的demo实现了隐藏js代码的方式,实现了一个条形图的基本交互方式,即Qt调用js脚本操作html。

 

Demo演示

  

 

ECharts调试工具

  ECharts提供的纯JS代码编辑开发调试工具,可编辑js,并且查看运行效果:
  https://echarts.apache.org/examples/zh/editor.html
  
  开发过程中对于属性的查询和调试ECharts也提供了配置帮助。
  官方配置手册:https://echarts.apache.org/zh/option.html
  

 

目标

  随便找一个预期目标:
  

 

ECharts接口静态方式

  使用EChart调试工具开发,先调试出基础框架。
  这里贴出的全部代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>ECharts</title>
<!-- 引入刚刚下载的 ECharts 文件 -->
<!--<script src="echarts.js"></script>-->
<script src="./echarts.js"></script>
<!--<script src="D:/qtProject/echartsDemo/echartsDemo/modules/barEChartWidget/html/echarts.js"></script>-->
<!--<script src="echarts.min.js"></script>-->
<!--<script src="./echarts.min.js"></script>-->
<!--<script src="./html/echarts.min.js"></script>-->
<!--<script src="D:/qtProject/echartsDemo/echartsDemo/modules/barEChartWidget/html/echarts.min.js"></script>-->
</head>
<body> <!--设置body跟随查u哪个口,main填充body-->
<style>
#main,
html,
body{
width: 100%;
height: 100%;
overflow: hidden;
}
#main {
width: 100%;
height: 100%;
}
</style> <div id="main"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 窗口高度变化设置
window.onresize = function() {
myChart.resize();
};
// 指定图表的配置项和数据
var option = {
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data: ['销量']
},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option); function initJs() {
var myChart = echarts.init(document.getElementById('main'));
var option;
option = {
tooltip: {
trigger: 'axis'
},
grid: {
left: '3%',
right: '4%',
bottom: '50',
containLabel: true
},
legend: {
orient: 'horizontal',
x: 'center',
y: 'bottom',
itemGap: 100
},
xAxis: {
type: 'value'
},
yAxis: {
type: 'category',
data: ['项目1', '项目2', '项目3']
},
series: [
{
name: '变量1',
type: 'bar',
stack: 'totla',
label: {
show: true
},
data: [11, 12, 13]
},
{
name: '子项目1',
type: 'bar',
stack: 'totla',
label: {
show: true
},
data: [24, 20, 21]
},
{
name: '变量3',
type: 'bar',
stack: 'totla',
label: {
show: true
},
data: [95, 87, 55]
}
]
};
};
initJs();
</script>
</body>
</html>
 

ECharts接口动态方式

  动态方式,最初目的是为了动态实现数据的js操作,在开发过程中发现动态方式还能隐藏echarts代码,使echarts代码不被抓取,最后决定全部改为动态加载方式。

步骤一:修改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>

步骤二:初始化

  新增了loadFinished信号槽关联。

void BarEChartWidget::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:/barEChartWidget/html/barEChartWidget.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 BarEChartWidget::slot_loadFinished(bool result)
{
if(result)
{
initJs();
}
}
void BarEChartWidget::initJs()
{
_initJsStr = QSTRING(
"var option;"
"option = {"
" tooltip: {"
" trigger: 'axis'"
" },"
" grid: {"
" left: '10',"
" right: '10',"
" top: '10',"
" bottom: 30,"
" containLabel: true"
" },"
" legend: {"
" orient: 'horizontal',"
" x: 'center',"
" y: 'bottom',"
" itemGap: 20"
" },"
" xAxis: {"
" type: 'value'"
" },"
" yAxis: {"
" type: 'category',"
" data: ['项目1', '项目2', '项目3']"
" },"
" series: ["
" {"
" name: '变量1',"
" type: 'bar',"
" stack: 'totla',"
" label: {"
" show: true"
" },"
" data: [11, 12, 13]"
" },"
" {"
" name: '变量2',"
" type: 'bar',"
" stack: 'totla',"
" label: {"
" show: true"
" },"
" data: [24, 20, 21]"
" },"
" {"
" name: '变量3',"
" type: 'bar',"
" stack: 'totla',"
" label: {"
" show: true"
" },"
" data: [95, 87, 55]"
" }"
" ]"
"};"
"myChart.setOption(option);");
runJsScript(_initJsStr);
} void BarEChartWidget::runJsScript(QString str)
{
if(_pWebEnginePage)
{
_pWebEnginePage->runJavaScript(str);
}
}

步骤四:动态执行js操作

重置

void BarEChartWidget::on_pushButton_reset_clicked()
{
initJs();
}

刷新

void BarEChartWidget::on_pushButton_flush_clicked()
{
QString jsStr =
"var empty = {};"
"myChart.setOption(empty, true);"
"myChart.setOption(option, true);";
runJsScript(jsStr);
}

清空

void BarEChartWidget::on_pushButton_clear_clicked()
{
QString jsStr =
"option.series[0].data = [];"
"option.series[1].data = [];"
"option.series[2].data = [];"
"myChart.setOption(option, true);";
runJsScript(jsStr);
}

随机生成(使用js代码)

void BarEChartWidget::on_pushButton_createRandom_clicked()
{
QString jsStr =
"var min = 0;"
"var max = 100;"
"for(var i = 0; i < option.series.length; i++)"
"{"
" for(var j = 0; j < option.yAxis.data.length; j++)"
" {"
" option.series[i].data[j] = Math.floor(Math.random() * (max - min)) + min;"
" }"
"}"
"myChart.setOption(option, true);";
runJsScript(jsStr);
}

  后续用会将数据进行Qt的一份缓存数据,由Qt的数据去生成ecahrts的js脚本。

 

Demo

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>

  在代码中使用js初始化echarts:
BarECartWidget.h

#ifndef BARECHARTWIDGET_H
#define BARECHARTWIDGET_H #include <QWidget>
#include <QWebEngineView>
#include <QWebEnginePage>
#include <QWebChannel> namespace Ui {
class BarEChartWidget;
} class BarEChartWidget : public QWidget
{
Q_OBJECT public:
explicit BarEChartWidget(QWidget *parent = 0);
~BarEChartWidget(); protected:
void initControl(); protected slots:
void slot_loadFinished(bool result); protected:
void initJs(); protected:
void runJsScript(QString str); protected:
void resizeEvent(QResizeEvent *event); private slots:
void on_pushButton_clear_clicked();
void on_pushButton_flush_clicked();
void on_pushButton_createRandom_clicked();
void on_pushButton_reset_clicked(); private:
Ui::BarEChartWidget *ui; private:
QWebEngineView *_pWebEngineView; // 浏览器窗口
QWebEnginePage *_pWebEnginePage; // 浏览器页面
QWebChannel *_pWebChannel; // 浏览器js交互 QString _htmlDir; // html文件夹路径
QString _indexFileName; // html文件 QString _initJsStr; // 第一次初始化的表格
}; #endif // BARECHARTWIDGET_H

BarEChartWidget.cpp

#include "BarEChartWidget.h"
#include "ui_BarEChartWidget.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") BarEChartWidget::BarEChartWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::BarEChartWidget),
_pWebEngineView(0),
_pWebEnginePage(0),
_pWebChannel(0),
_htmlDir("D:/qtProject/echartsDemo/echartsDemo/modules/barEChartWidget/html"), // 使用了绝对路径,引到html文件夹
_indexFileName("barEChartWidget.html")
{
ui->setupUi(this); QString version = "v1.0.0";
setWindowTitle(QString("基于Qt的ECharts条状图Demo %1(长沙红胖子 QQ:21497936 WX:15173255813 blog:hpzwl.blog.csdn.net").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();
} BarEChartWidget::~BarEChartWidget()
{
delete ui;
} void BarEChartWidget::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:/barEChartWidget/html/barEChartWidget.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 BarEChartWidget::slot_loadFinished(bool result)
{
if(result)
{
initJs();
}
} void BarEChartWidget::initJs()
{
_initJsStr = QSTRING(
"var option;"
"option = {"
" tooltip: {"
" trigger: 'axis'"
" },"
" grid: {"
" left: '10',"
" right: '10',"
" top: '10',"
" bottom: 30,"
" containLabel: true"
" },"
" legend: {"
" orient: 'horizontal',"
" x: 'center',"
" y: 'bottom',"
" itemGap: 20"
" },"
" xAxis: {"
" type: 'value'"
" },"
" yAxis: {"
" type: 'category',"
" data: ['项目1', '项目2', '项目3']"
" },"
" series: ["
" {"
" name: '变量1',"
" type: 'bar',"
" stack: 'totla',"
" label: {"
" show: true"
" },"
" data: [11, 12, 13]"
" },"
" {"
" name: '变量2',"
" type: 'bar',"
" stack: 'totla',"
" label: {"
" show: true"
" },"
" data: [24, 20, 21]"
" },"
" {"
" name: '变量3',"
" type: 'bar',"
" stack: 'totla',"
" label: {"
" show: true"
" },"
" data: [95, 87, 55]"
" }"
" ]"
"};"
"myChart.setOption(option);");
runJsScript(_initJsStr);
} void BarEChartWidget::runJsScript(QString str)
{
if(_pWebEnginePage)
{
_pWebEnginePage->runJavaScript(str);
}
} void BarEChartWidget::resizeEvent(QResizeEvent *event)
{
if(_pWebEngineView)
{
_pWebEngineView->setGeometry(ui->label_echarts->geometry());
}
} void BarEChartWidget::on_pushButton_clear_clicked()
{
QString jsStr =
"option.series[0].data = [];"
"option.series[1].data = [];"
"option.series[2].data = [];"
"myChart.setOption(option, true);";
runJsScript(jsStr);
} void BarEChartWidget::on_pushButton_flush_clicked()
{
QString jsStr =
"var empty = {};"
"myChart.setOption(empty, true);"
"myChart.setOption(option, true);";
runJsScript(jsStr);
} void BarEChartWidget::on_pushButton_createRandom_clicked()
{
QString jsStr =
"var min = 0;"
"var max = 100;"
"for(var i = 0; i < option.series.length; i++)"
"{"
" for(var j = 0; j < option.yAxis.data.length; j++)"
" {"
" option.series[i].data[j] = Math.floor(Math.random() * (max - min)) + min;"
" }"
"}"
"myChart.setOption(option, true);";
runJsScript(jsStr);
} void BarEChartWidget::on_pushButton_reset_clicked()
{
initJs();
}
 

入坑

入坑一:调用js函数失败

问题

  通过qt代码跑js调用函数失败。
  

  

原理

  先要等页面加载完成后才能调用定义的函数。

解决

  发现是调用成功了,原来只定义也会报这个错误。
   
  由此可以看出,在qt中去初始化需要等待页面加载完成才行。

入坑二:Qt的msvc编译器少数中文乱码

问题

  少数中文乱码,加空格等都无法解决。
  

解决

  最终解决了,尝试了QTextCodec等各种都不行,最终:
  
  

 

工程模板v1.2.0

  

 

后话

  条形图将会根据实际需求持续升级版本,下一篇会继续折线图的基础封装。

Qt+ECharts开发笔记(三):ECharts的柱状图介绍、基础使用和Qt封装Demo的更多相关文章

  1. Django开发笔记三

    Django开发笔记一 Django开发笔记二 Django开发笔记三 Django开发笔记四 Django开发笔记五 Django开发笔记六 1.基于类的方式重写登录:views.py: from ...

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

    前言   上一篇的demo使用隐藏js代码的方式,实现了一个饼图的基本交互方式,并预留了Qt模块对外的基础接口.  本篇的demo实现了自动排序的柱状图,实现了一个自动排序柱状图的基本交互方式,即Qt ...

  3. Qt+ECharts开发笔记(二):Qt窗口动态调整大小,使ECharts跟随Qt窗口大小变换而变换大小

    前言   上一篇将ECharts嵌入Qt中,在开始ECharts使用之前,还有一个很重要的功能,就是在窗口变换大小的时候,ECharts的图表尺寸也要跟随Qt窗口变换大小而变换大小.   Demo演示 ...

  4. Qt+ECharts开发笔记(四):ECharts的饼图介绍、基础使用和Qt封装百分比图Demo

    前言   前一篇介绍了横向柱图图.本篇将介绍基础饼图使用,并将其封装一层Qt.  本篇的demo使用隐藏js代码的方式,实现了一个饼图的基本交互方式,并预留了Qt模块对外的基础接口.   Demo演示 ...

  5. TERSUS无代码开发(笔记01)-按装下载和基础语法

    1.中国官网 https://tersus.cn/ 2.下载:https://tersus.cn/download/ 3.开发文档:https://tersus.cn/docs/ 4.基本元件说明 图 ...

  6. echarts使用笔记三:柱子对比

    app.title = '坐标轴刻度与标签对齐'; option = { title : { //标题 x : 'center', y : 5, text : '对比图' //换行用 \n }, le ...

  7. 麒麟系统开发笔记(二):国产麒麟系统搭建Qt开发环境安装Qt5.12

    前言   开发国产应用,使用到银河麒麟V4,V10,本篇以V10记录,参照上一篇可安装V4.V7.V10三个版本,麒麟V4系自带了Qt,麒麟V10没有自带Qt,需要自己编译搭建环境.   银河麒麟V1 ...

  8. ECharts学习总结(三):ECharts图表对象的初始化(init)详解以及注意事项

    一.相关js文件的引入 这里我们采用标签式引入文件的方式,我们引入两个js文件,一个是esl.js文件和一个echarts.js. <script src="js/esl.js&quo ...

  9. RBL开发笔记三

    2014-08-26 20:06:24 今天就是在开发这个EPOLL来处理网络事件 封装较为健壮的EPOLL模型来处理基本的网络IO 1) 超时这个主题先没有弄 在开发EPOLL包括select/po ...

随机推荐

  1. 批量安装Windows系统

    今天我们利用Windows server 2019自带的Windows部署服务通过网络批量安装Win 10 一.Windows服务 1)WDS WDS(Windows Deployment Servi ...

  2. Windows与Linux如何实现相互远程桌面连接?

    今天跟大家一起讨论下,利用Windows自带的远程桌面连接工具,实现远程Linux桌面及在Linux系统中远程Windows桌面 一.Windows远程Linux桌面 1)本次实验以CentOS 7. ...

  3. go convert slice to struct

    Question: in golang how to convert slice to struct scene 1:use reflect convert slice to struct func ...

  4. 面试官:RocketMQ是什么,它有什么特性与使用场景?

    哈喽!大家好,我是小奇,一位热爱分享的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 作为一名Java程序员,Roc ...

  5. 为什么说 Gradle 是 Android 进阶绕不去的坎 —— Gradle 系列(1)

    请点赞,你的点赞对我意义重大,满足下我的虚荣心. Hi,我是小彭.本文已收录到 GitHub · Android-NoteBook 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,欢迎 ...

  6. 日期和时间API - 读《Java 8实战》

    日期与时间 LocalDate 创建一个LocalDate对象并读取其值 // 根据年月日创建日期 LocalDate date1 = LocalDate.of(2014, 3, 18); // 读取 ...

  7. K8S Flannel网络插件

    0.前言 参考文档:https://github.com/containernetworking/cni Pod网络插件,为了实现Pod网络而需要的插件.组件.由于Kubernetes通过开放的CNI ...

  8. 羽夏笔记—— AT&T 与 GCC

    写在前面   本文是本人根据<AT&T 汇编语言与 GCC 内嵌汇编简介>进一步整理,修改了一些错误,并删除我并不能复现代码相关的部分.该文章一是我对 AT&T 的学习记录 ...

  9. 【Azure 存储服务】Java Azure Storage SDK V12使用Endpoint连接Blob Service遇见 The Azure Storage endpoint url is malformed

    问题描述 使用Azure Storage Account的共享访问签名(Share Access Signature) 生成的终结点,连接时遇见  The Azure Storage endpoint ...

  10. 绿色城市智慧运营:Web 3D 垃圾分类 GIS 系统

    前言 感谢所有为上海疫情奉献的人,祈求上海疫情早日清零,中国加油,上海加油! <上海市生活垃圾管理条例>施行至今已有两年多,上海市民践行绿色低碳理念.主动参与生活垃圾分类的习惯基本养成,分 ...