Qt调用Echarts显示动态过程曲线
效果
先来看看效果吧。
Qt生成随机数发送给Echarts,1000ms刷新一次
环境
具体配置见我的另外一篇最清晰Qt与JS通过qwebchannel交互例子
备注:
1.HTML端就是最基本的HTML、JS,没有更高层的
2.基础知识:Echarts相关基本知识
HTML端代码Echarts
在上一篇文章HTML目类下新建一个echarttest.html
文件,修改Echarts例子给出的部分HTML代码,然后Qt调用这个页面
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<!-- 引入 ECharts 文件 -->
<script src="D:/Code/JS/Echart/echarts.min.js"></script>
<script src="qwebchannel.js"></script>
</head>
<p id="xlabel">x:</p>
<p id="ylabel">y:</p>
<body>
<!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
<div id="main" class="chart" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
//自适应宽高
var resizeContainer = function () {
var myChart = document.getElementById('main');
myChart.style.width = window.innerWidth - 32 + 'px'; //
myChart.style.height = window.innerHeight - 100 + 'px'; //适应Qt内嵌边框
};
resizeContainer();
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
title: {
text: 'Qt实时传输数据调用ECharts示例',
left: '40%'
},
grid: {
left: '5%',
right: '3%',
top: '10%',
bottom: '8%'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['值'],
right: '10%',
top: '5%'
},
xAxis: {
data: []
},
yAxis: {},
series: [{
name: '值',
type: 'line',
data: []
}]
};
myChart.setOption(option);
//自适应窗口大小
window.onresize = function () {
resizeContainer();
myChart.resize();
};
//接受从Qt来的数据
var x = [];
var y = [];
new QWebChannel(qt.webChannelTransport, function (channel) {
var webobj = channel.objects.webobj;
//arg-QJsonObject类型
webobj.dataChanged.connect(function (arg) {
xlabel.innerHTML = "x:" + arg.x;
ylabel.innerHTML = "y:" + arg.y.toFixed(4);
x.push(arg.x);
y.push(arg.y.toFixed(4));
myChart.setOption({
xAxis: {
data: x
},
series: [{
name: '值',
data: y
}]
});
});
});
</script>
</body>
</html>
Qt端修改代码
.h
文件
class WebClass : public QObject
{
Q_OBJECT
Q_PROPERTY(QJsonObject jsonData MEMBER m_jsonData NOTIFY dataChanged)
public:
signals:
void dataChanged(const QJsonObject &jsonData);
private:
QJsonObject m_jsonData;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
QWebEngineView *webView = nullptr;
QWebChannel *webChannel = nullptr;
WebClass *webobj = nullptr;
QPushButton *btn = nullptr;
QTimer *timer = nullptr;
QJsonObject json;
};
.cpp
文件
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
btn = new QPushButton("..");
connect(btn, &QPushButton::clicked, this,
[&]()
{
timer = new QTimer;
connect(timer, &QTimer::timeout, this,
[&]()
{
static int index = 0;
json["x"] = index++;
//生成随机数
json["y"] = QRandomGenerator::global()->generateDouble() * 10;
webobj->setProperty("jsonData", json);
});
timer->start(1000);
});
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(btn, 1, Qt::AlignLeft);
webView = new QWebEngineView(parent);
webView->load(QUrl::fromLocalFile("D:\\Code\\JS\\test.html"));
layout->addWidget(webView);
QWidget *w = new QWidget;
w->setLayout(layout);
setCentralWidget(w);
webChannel = new QWebChannel;
webobj = new WebClass();
webChannel->registerObject("webobj", webobj);
webView->page()->setWebChannel(webChannel);
setMinimumSize(800, 600);
}
x坐标是时间类型
上一个例子还是横坐标还是普通数据,如果是时间型的呢?这会涉及到QString和Json日期换算的问题,稍微花点时间完成了,顺便将几个类简单封装了下,另外Echarts里的一个重要特性加上了,仍然是Qt生成随机数实时发送给JS。效果如下
具体代码如下:
HTML端
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<!-- 引入 ECharts 文件 -->
<script src="echarts.min.js"></script>
<script src="qwebchannel.js"></script>
</head>
<table width="300" border="0">
<tr>
<td id="xlabel">x:</td>
<td id="ylabel">y:</td>
<td id="zlabel">z:</td>
</tr>
</table>
<body>
<!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
<div id="main" class="chart" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
//自适应宽高
var resizeContainer = function () {
var myChart = document.getElementById('main');
myChart.style.width = window.innerWidth - 20 + 'px'; //
myChart.style.height = window.innerHeight - 50 + 'px'; //适应Qt内嵌边框
};
//字符串转日期 yyyy-MM-dd hh:mm:ss
function str2Datetime(strDateTime) {
var tempStrs = strDateTime.split(" ");
var dateStrs = tempStrs[0].split("-");
var year = parseInt(dateStrs[0], 10);
var month = parseInt(dateStrs[1], 10) - 1;
var day = parseInt(dateStrs[2], 10);
var timeStrs = tempStrs[1].split(":");
var hour = parseInt(timeStrs[0], 10);
var minute = parseInt(timeStrs[1], 10);
var second = parseInt(timeStrs[2], 10);
var datetime = new Date(year, month, day, hour, minute, second);
return datetime;
}
resizeContainer();
var myChart = echarts.init(document.getElementById('main'), 'light');
// 指定图表的配置项和数据
var option = {
title: {
text: 'Qt实时传输数据调用ECharts示例',
left: 'center'
},
grid: {
left: '5%',
right: '8%',
top: '10%',
bottom: '12%',
show: false
},
toolbox: {
right: '13%',
feature: {
dataZoom: {
yAxisIndex: 'none'
},
restore: {}
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
legend: {
data: ['流量', '降雨量'],
left: '10%',
top: '5%'
},
xAxis: {
axisTick: {
alignWithLabel: true
},
data: []
},
yAxis: [{
name: '流量(m^3/h)',
type: 'value',
axisLine: {
lineStyle: {
color: '#333',
width: 2
}
},
axisPointer: {
show: false
}
},
{
name: '降雨量(mm)',
nameLocation: 'start',
type: 'value',
axisLine: {
lineStyle: {
color: '#aaa',
width: 2
}
},
inverse: true,
axisPointer: {
show: false
}
}
],
dataZoom: [{
type: 'slider',
show: true,
xAxisIndex: [0],
start: 0,
end: 100,
bottom: 3
},
{
type: 'inside',
show: true,
xAxisIndex: [0],
start: 0,
end: 100
}
],
series: [{
name: '流量',
type: 'line',
data: []
},
{
name: '降雨量',
yAxisIndex: 1,
type: 'bar',
data: []
}
]
};
myChart.setOption(option);
//自适应窗口大小
window.onresize = function () {
resizeContainer();
myChart.resize();
};
//接受从Qt来的数据
var x = [];
var y = [];
var z = [];
new QWebChannel(qt.webChannelTransport, function (channel) {
var jsondata = channel.objects.eChartdata;
//arg-QJsonObject类型
jsondata.dataChanged.connect(function (arg) {
xlabel.innerHTML = "time:" + arg.x;
ylabel.innerHTML = "y:" + arg.y.toFixed(4);
zlabel.innerHTML = "z:" + arg.z.toFixed(4);
var date = str2Datetime(arg.x);
var hour = date.getHours();
var min = date.getMinutes();
var sec = date.getSeconds();
x.push(hour + ':' + min + ':' + sec);
y.push(arg.y.toFixed(4));
z.push(arg.z.toFixed(4));
myChart.setOption({
xAxis: {
data: x
},
series: [{
name: '流量',
data: y
},
{
name: '降雨量',
data: z
}
]
});
});
});
</script>
</body>
</html>
Qt端
class EchartDataClass : public QObject
{
Q_OBJECT
Q_PROPERTY(QJsonObject jsonData MEMBER m_jsonData NOTIFY dataChanged)
public:
signals:
void dataChanged(const QJsonObject &jsonData);
private:
QJsonObject m_jsonData;
};
class EchartWidget : public QWidget
{
Q_OBJECT
public:
EchartWidget(const QString &htmlPath, QWidget *parent = nullptr) : QWidget(parent)
{
QVBoxLayout *layout = new QVBoxLayout;
webView = new QWebEngineView(parent);
webView->load(QUrl::fromLocalFile(htmlPath));
layout->addWidget(webView);
webChannel = new QWebChannel;
eChartdata = new EchartDataClass;
webChannel->registerObject("eChartdata", eChartdata);
webView->page()->setWebChannel(webChannel);
setLayout(layout);
layout->setMargin(0);
setMinimumSize(800, 600);
}
void setData(QDateTime dt, double y, double z)
{
QJsonObject json;
json["x"] = dt.toString("yyyy-MM-dd hh:mm:ss");
json["y"] = y;
json["z"] = z;
eChartdata->setProperty("jsonData", json);
}
virtual ~EchartWidget()
{
}
private:
QWebEngineView *webView = nullptr;
QWebChannel *webChannel = nullptr;
EchartDataClass *eChartdata = nullptr;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
QPushButton *btn = nullptr;
QTimer *timer = nullptr;
EchartWidget *echartWidget = nullptr;
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
btn = new QPushButton("start");
connect(btn, &QPushButton::clicked, this,
[&]()
{
if (btn->text() == "start")
{
btn->setText("stop");
if (timer == nullptr)
{
timer = new QTimer;
connect(timer, &QTimer::timeout, this,
[&]()
{
echartWidget->setData(QDateTime::currentDateTime(),
QRandomGenerator::global()->generateDouble() * 10,
QRandomGenerator::global()->generateDouble());
});
}
timer->start(1000);
}
else
{
btn->setText("start");
timer->stop();
}
});
QVBoxLayout *layout = new QVBoxLayout;
layout->setMargin(0);
layout->addWidget(btn, 1, Qt::AlignLeft);
echartWidget
= new EchartWidget("D:\\Code\\JS\\test.html");
layout->addWidget(echartWidget);
QWidget *w = new QWidget;
w->setLayout(layout);
setCentralWidget(w);
}
参考文献
最清晰Qt与JS通过qwebchannel交互例子
Qt WebChannel JavaScript API
echart官方例子