当前位置: 首页 > news >正文

Qt Graphs 模块拟取代 charts 和 data visualization还有很长的路要走

近期关注 Qt 6.10 的分支进展, 发现了 Qt 6.10 的 charts 和 data visualization (以下简称 DV)已经被deprecated, 功能将会合并到 graphs 模块。如果后面 charts\ DV 被弃用,那算是很大的API变化了。从Qt 6.5 以后开始引入的 graphs 使用的是QML的渲染器,和之前的 Qt Widgets GraphicsView 完全不同。如果有依赖上述模块的应用,需要提前评估API的变化。

1. 可能遇到的主要问题

只要是和QML相关的东西,那问题无外乎就是老电脑的兼容性,以及跨语言的API。

1.1 老旧和低成本环境可能不再适用

QML的渲染器过度依赖OS的本地3D加速API,如 Windows的 DirectX。在VMWare/VirtualBox环境下,QML有概率无法正常渲染图形。在只有核心显卡,没有配置独立显卡的低成本计算机上,QML也非常卡顿,甚至可能无法启动(如果驱动比较老或者配置不正确)。

与之形成对比的,是Widgets的2D渲染,基本是在backend里自绘的,因此,不但可以支持老旧计算机,还能在 vnc、framebuf里使用。

1.2 跨语言API调用和性能问题

charts和DV是支持C++ Only模式的开发的。但是, graphs 却不是。官网的例子里,C++ Widgets 程序使用 graphs 必须要进行QML混合编程。这里就牵扯到三个场景:

  1. 从C++中动态向 QML 刷新曲线,特别是1秒刷新23次的这种动画。
  2. 从C++中精确获得QML图元的signal,如橡皮筋选择、有图元被双击等等。
  3. 从C++中查询各个图元的属性和状态。比如查询视图的宽度、高度,选中的状态等。

这些操作要达到高性能、易于使用,需要特别注意不出现内存深度拷贝,且管理好QObject对象树的生命周期(life-cycle)。

2. 初步试用

抱着试试看的态度,初步对 Qt Graphs的API进行了研究,并以最简单的动态折线图进行了开发测试。

pro文件

模块包括 quickwidgets graphs quick 等模块。

QT       += core gui widgets quickwidgets graphs quickCONFIG += c++17SOURCES += \main.cpp \graphstest.cppHEADERS += \graphstest.hFORMS += \graphstest.ui

2.2 main.cpp

#include "graphstest.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);graphsTest w;w.show();return a.exec();
}

2.3 graphstest.h

#ifndef GRAPHSTEST_H
#define GRAPHSTEST_H#include <QDateTimeAxis>
#include <QDialog>
#include <QLineSeries>
#include <QValueAxis>
#include <QVector>
QT_BEGIN_NAMESPACE
namespace Ui
{
class graphsTest;
}
QT_END_NAMESPACEclass graphsTest : public QDialog
{Q_OBJECTpublic:graphsTest(QWidget *parent = nullptr);~graphsTest();protected:void timerEvent(QTimerEvent *evt) override;
private slots:void on_pushButton_add_clicked();void on_checkBox_update_clicked();private:Ui::graphsTest *ui;QDateTimeAxis *m_ax;QValueAxis *m_ay;int m_timerEvent;QVector<QLineSeries *> m_lineSeries;
};
#endif // GRAPHSTEST_H

2.4 graphstest.cpp

#include "graphstest.h"
#include <QDateTime>
#include <QDebug>
#include <QQuickItem>
#include "ui_graphstest.h"
graphsTest::graphsTest(QWidget *parent): QDialog(parent), ui(new Ui::graphsTest), m_ax(new QDateTimeAxis(this)), m_ay(new QValueAxis(this)), m_timerEvent(-1)
{ui->setupUi(this);QDateTime dtmNow = QDateTime::currentDateTime();m_ax->setMin(dtmNow.addDays(-1));m_ax->setMax(dtmNow);m_ay->setRange(-100, 100);QList<QObject *> seriesList;ui->graphsView->setResizeMode(QQuickWidget::SizeRootObjectToView);ui->graphsView->setInitialProperties({{"seriesList", QVariant::fromValue(seriesList)},{"axisX", QVariant::fromValue(m_ax)},{"axisY", QVariant::fromValue(m_ay)},{"zoomAreaEnabled", true}});ui->graphsView->loadFromModule("QtGraphs", "GraphsView");
}graphsTest::~graphsTest()
{delete ui;
}void graphsTest::timerEvent(QTimerEvent *evt)
{if (evt->timerId() == m_timerEvent){QList<QPointF> data;QDateTime dtmNow = QDateTime::currentDateTime();const int N = m_lineSeries.size();for (int n = 0; n < N; ++n){for (int i = 0; i < 30; ++i){data << QPointF(dtmNow.addSecs(-3600 * 24.0 / 30 * (29 - i)).toMSecsSinceEpoch(),(rand() % 500 - 250) / 100.0 + n * 16 - 80);}m_lineSeries[n]->replace(data);}m_ax->setMin(dtmNow.addDays(-1));m_ax->setMax(dtmNow);if (!ui->checkBox_update->isChecked()){killTimer(m_timerEvent);m_timerEvent = -1;}}QDialog::timerEvent(evt);
}void graphsTest::on_pushButton_add_clicked()
{if (m_lineSeries.size() >= 10)return;//Add to GraphQVariant seriesListVariant = ui->graphsView->rootObject()->property("seriesList");if (seriesListVariant.canConvert<QQmlListProperty<QObject>>()){QLineSeries *newLine = new QLineSeries(this);newLine->setColor(QColor(rand() % 128, rand() % 128, rand() % 128));newLine->setHoverable(true);newLine->setName(QString("Testing %1").arg(m_lineSeries.size()));connect(newLine,&QAbstractSeries::hover,[this](const QString &seriesName, QPointF position, QPointF value) -> void{ui->lineEdit_msg->setText(QString("%1:%2 %3 = %4 %5").arg(seriesName).arg(position.x()).arg(position.y()).arg(value.x()).arg(value.y()));});//AddQQmlListProperty<QObject> prop = seriesListVariant.value<QQmlListProperty<QObject>>();prop.append(&prop, newLine);m_lineSeries.append(newLine);}if (m_timerEvent < 0)m_timerEvent = startTimer(500);
}void graphsTest::on_checkBox_update_clicked()
{if (ui->checkBox_update->isChecked())m_timerEvent = startTimer(500);
}

2.5 graphstest.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>graphsTest</class><widget class="QDialog" name="graphsTest"><property name="geometry"><rect><x>0</x><y>0</y><width>579</width><height>332</height></rect></property><property name="windowTitle"><string>graphsTest</string></property><layout class="QVBoxLayout" name="verticalLayout_2"><item><layout class="QHBoxLayout" name="horizontalLayout"><item><widget class="QQuickWidget" name="graphsView"><property name="resizeMode"><enum>QQuickWidget::ResizeMode::SizeRootObjectToView</enum></property></widget></item><item><layout class="QVBoxLayout" name="verticalLayout"><property name="sizeConstraint"><enum>QLayout::SizeConstraint::SetMaximumSize</enum></property><item><widget class="QPushButton" name="pushButton_add"><property name="sizePolicy"><sizepolicy hsizetype="Fixed" vsizetype="Fixed"><horstretch>0</horstretch><verstretch>0</verstretch></sizepolicy></property><property name="text"><string>Add Serials</string></property></widget></item><item><widget class="QCheckBox" name="checkBox_update"><property name="sizePolicy"><sizepolicy hsizetype="Maximum" vsizetype="Fixed"><horstretch>0</horstretch><verstretch>0</verstretch></sizepolicy></property><property name="text"><string>Updating</string></property></widget></item><item><spacer name="verticalSpacer"><property name="sizePolicy"><sizepolicy hsizetype="Fixed" vsizetype="Expanding"><horstretch>0</horstretch><verstretch>0</verstretch></sizepolicy></property><property name="orientation"><enum>Qt::Orientation::Vertical</enum></property><property name="sizeHint" stdset="0"><size><width>20</width><height>40</height></size></property></spacer></item></layout></item></layout></item><item><widget class="QLineEdit" name="lineEdit_msg"><property name="sizePolicy"><sizepolicy hsizetype="Expanding" vsizetype="Fixed"><horstretch>0</horstretch><verstretch>0</verstretch></sizepolicy></property></widget></item></layout></widget><customwidgets><customwidget><class>QQuickWidget</class><extends>QWidget</extends><header location="global">QtQuickWidgets/QQuickWidget</header></customwidget></customwidgets><resources/><connections/>
</ui>

3. 运行效果

运行效果如下,主要问题包括(BUG):

  1. 新插入的对象的色彩,会影响到旧对象的色彩。
  2. 各个连线的收尾会连接起来。

add

4 评价

Qt 团队看起来对传统的 Widgets 已经不是很愿意维护了,这种大规模的API变化,以及完全不顾及兼容老计算机、集成显卡的环境的激进改进,要么是公司no zuo no die,要么说明QML技术的趋势已经势不可挡。

QML技术与C++的紧密互动,相当程度的缓解了API跨语言的问题,其实QML就是个调用C++ QObject 运行时的胶水语言,其和C++的联系非常紧密。对Qt Widgets而言,如果使用了 QML的功能,就会在硬件兼容性上面大打折扣,这对于很多桌面场景而言是不能接受的。对未来技术的发展,我们会保持持续的跟踪,并适时为我们使用 charts 的既有代码进行 graphs的适配,并在具备 charts 的环境下优先使用 charts.

http://www.dtcms.com/a/288021.html

相关文章:

  • 完美解决 Ubuntu 中自定义启动器图标重复的问题(以 MATLAB 为例)
  • 游戏开发日志
  • 操作系统-进程同步机制
  • 搭建比分网服务器怎么选数据不会卡顿?
  • SEO长尾关键词优化实战指南抢占市场
  • 基于DTLC-AEC与DTLN的轻量级实时语音增强系统设计与实现
  • 你的网站正在被Google最新算法惩罚吗?
  • SpringJDBC源码初探-JdbcTemplate类
  • xss的利用
  • 博图SCL语言中常用运算符使用详解及实战案例(下)
  • 抖音回应:没有自建外卖,就是在团购的基础上增加的配送功能
  • 前端开发技巧:浏览器模拟弱网络环境
  • Streamlit 官翻 4 - 快速参考、知识库 Quick Reference
  • 电脑windows系统深度维护指南
  • 网络包从客户端发出到服务端接收的过程
  • 初识C++——开启新旅途
  • 【每日算法】专题十五_BFS 解决 FloodFill 算法
  • Xshell若依项目部署到云服务器
  • 考研408《计算机组成原理》复习笔记,第三章(5)——磁盘存储器
  • react+antd 可拖拽模态框组件
  • 智能设备畅想
  • AWD练习的平台搭建
  • 牛客-倒置字符串
  • 如何使用orthofinder进行同源基因鉴定
  • 【Web APIs】JavaScript 自定义属性操作 ② ( H5 自定义属性 )
  • Node.js dns 模块深入解析
  • python的第三方库的基本运用
  • node.js学习笔记1
  • Tomcat配置和部署项目
  • 从零手写红黑树(C++实现详解)