前言

  qt提供了q3d进行三维开发,虽然这个框架没有得到大量运用也不是那么成功,性能上也有很大的欠缺,但是普通的点到为止的应用展示还是可以的。
  其中就包括华丽绚烂的三维图表,数据量不大的时候是可以使用的。

 

Demo:Q3DScatter散点图演示效果

  
   
  

 

Q3D提供的三维图表

  依赖QtDataVisualization。在安装qt的时候要选择安装QtDataVisualization模块。

Q3DScatter散点图

  Q3D的散点图,性能大约支撑1000个点可以不卡顿,具体依赖pc,1000个点是什么 概念,可以理解为:10x10x10的区域,每个区域一个数据点。
  

Q3DBars柱状图

  Q3D的柱状图,性能跟散点图类似。
  

Q3DSurface平面凹凸图,平面纹理图

  Q3D的柱状图,性能跟散点图类似。
  

 

Q3DScatter散点图

简介

  Q3DScatter类提供了渲染3D散点图的方法。能够在3D中渲染散点图,并通过自由旋转场景来查看散点图。
  旋转是通过按住鼠标右键并移动鼠标来完成的。缩放由鼠标滚轮完成。如果启用,则通过鼠标左键进行选择。通过单击鼠标滚轮,可以将场景重置为默认摄影机视图。在触摸设备中,旋转是通过点击和移动完成的,选择是通过点击并按住并缩放。
  如果没有设置轴,将创建没有标签的临时默认轴。这些默认轴可以通过轴访问器进行修改,但是一旦为方向明确设置了任何轴,该方向的默认轴就会被破坏。
  Q3DScatter支持同时显示多个系列。

构造最小Q3DS散点图

  首先,构建Q3DS散射器。由于在本例中我们将图形作为顶级窗口运行,因此需要清除Qt::FramelessWindowHint标志,该标志默认设置为:

Q3DScatter scatter;
scatter.setFlags(scatter.flags() ^ Qt::FramelessWindowHint);

  现在Q3DScatter已准备好接收要渲染的数据。添加一系列3个QVector3D项目:

QScatter3DSeries *series = new QScatter3DSeries;
QScatterDataArray data;
data << QVector3D(0.5f, 0.5f, 0.5f) << QVector3D(-0.3f, -0.5f, -0.4f) << QVector3D(0.0f, -0.3f, 0.2f);
series->dataProxy()->addItems(data);
scatter.addSeries(series);

  最后,将其设置为可见:

scatter.show();

  创建和显示此图形所需的完整代码是:

#include <QtDataVisualization>

using namespace QtDataVisualization;

int main(int argc, char **argv)
{
QGuiApplication app(argc, argv); Q3DScatter scatter;
scatter.setFlags(scatter.flags() ^ Qt::FramelessWindowHint);
QScatter3DSeries *series = new QScatter3DSeries;
QScatterDataArray data;
data << QVector3D(0.5f, 0.5f, 0.5f)
<< QVector3D(-0.3f, -0.5f, -0.4f)
<< QVector3D(0.0f, -0.3f, 0.2f);
series->dataProxy()->addItems(data);
scatter.addSeries(series);
scatter.show(); return app.exec();
}

  运行效果:
  
  场景可以被旋转、放大,并且可以选择一个项目来查看其位置,但在这个最小的代码示例中不包括其他交互。通过熟悉所提供的示例(如散点示例)来了解更多信息。

 

Q3Ddemo构建流程解析

步骤一:确认安装QtDataVisualization模块

  如何确认,则是在帮助文件中查看是否有Q3dscatter类。一般是安装了模块才会有对应的帮助文件。没有则重新安装qt或者单独安装该模块。
  

步骤二:工程配置文件中加入模块

  Q3d是在数据可视化模块中,需要在pro或者pri配置文件中添加。

QT += datavisualization

  

步骤三:添加使用到的头文件

  使用到Q3DScatter相关类中添加头文件,主要使用到Q3DScatter和QScatter3DSeries等等。

#include <Q3DScatter>
#include <Q3DTheme>
#include <QScatter3DSeries>
#include <QVector3D>

  

步骤四:添加命名空间

  这时候还是无法使用对应的类,需要添加命名空间才行,查看最后“入坑一”:

using namespace QtDataVisualization;

  

步骤五:Q3D的图标基础构建框架

  下面是包含注释的Q3DScatter基础构建流程,其他两种图类似:

_pQ3DScatter = new Q3DScatter();
_pContainer = QWidget::createWindowContainer(_pQ3DScatter, this); // 设置轴文本
{
_pQ3DScatter->axisX()->setTitle("X");
_pQ3DScatter->axisY()->setTitle("Y");
_pQ3DScatter->axisZ()->setTitle("Z");
}
// 设置轴范围
{
// _pQ3DScatter->axisX()->setRange(0, 10);
// _pQ3DScatter->axisY()->setRange(0, 10);
// _pQ3DScatter->axisZ()->setRange(0, 10);
} // 生成一个曲线
_pScatter3DSeries = new QScatter3DSeries(_pQ3DScatter);
// 设置渲染平滑
_pScatter3DSeries->setMeshSmooth(true); // 视图添加该曲线
_pQ3DScatter->addSeries(_pScatter3DSeries); // 设置阴影质量
_pQ3DScatter->setShadowQuality(QAbstract3DGraph::ShadowQualitySoftLow);
// 设置视角
_pQ3DScatter->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetIsometricLeft);
// 设置子网格
_pQ3DScatter->activeTheme()->setGridEnabled(true); #if 1
// 添加模拟数据
QScatterDataArray data;
data << QVector3D(1, 1,1) << QVector3D(1, 1, 2) << QVector3D(1, 1, 3)
<< QVector3D(1, 2,1) << QVector3D(1, 2, 2) << QVector3D(1, 2, 3)
<< QVector3D(1, 3,1) << QVector3D(1, 3, 2) << QVector3D(1, 3, 3);
// 添加数据(自动冲掉之前的数据)
_pScatter3DSeries->dataProxy()->addItems(data);
#endif #if 1
// 模拟
QList<QVector3D> listVector3D;
#if 0
listVector3D << QVector3D(5, 1,1) << QVector3D(5, 1, 2) << QVector3D(5, 1, 3)
<< QVector3D(5, 2,1) << QVector3D(5, 2, 2) << QVector3D(5, 2, 3)
<< QVector3D(5, 3,1) << QVector3D(5, 3, 2) << QVector3D(5, 3, 3);
#else
listVector3D << QVector3D(1, 1,1) << QVector3D(1, 1, 2) << QVector3D(1, 1, 3)
<< QVector3D(1, 2,1) << QVector3D(1, 2, 2) << QVector3D(1, 2, 3)
<< QVector3D(1, 3,1) << QVector3D(1, 3, 2) << QVector3D(1, 3, 3);
#endif
 

Demo源码

Q3dScatterWidget.h

#ifndef Q3DSCATTERWIDGET_H
#define Q3DSCATTERWIDGET_H #include <QWidget>
#include <Q3DScatter>
#include <Q3DTheme>
#include <QScatter3DSeries>
#include <QVector3D> using namespace QtDataVisualization; namespace Ui {
class Q3dScatterWidget;
} class Q3dScatterWidget : public QWidget
{
Q_OBJECT public:
explicit Q3dScatterWidget(QWidget *parent = 0);
~Q3dScatterWidget(); public:
void setData(QList<QVector3D> listVector3D); protected:
void initControl(); protected:
void resizeEvent(QResizeEvent *event); private:
Ui::Q3dScatterWidget *ui; private:
Q3DScatter *_pQ3DScatter; // q3d散点视图
QWidget *_pContainer; // q3d窗口容器
QScatter3DSeries *_pScatter3DSeries; // q3d散点图数据
}; #endif // Q3DSCATTERWIDGET_H

Q3dScatterWidget.cpp

#include "Q3dScatterWidget.h"
#include "ui_Q3dScatterWidget.h"
#include <Q3DTheme> #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") Q3dScatterWidget::Q3dScatterWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Q3dScatterWidget),
_pQ3DScatter(0),
_pContainer(0),
_pScatter3DSeries(0)
{
ui->setupUi(this); QString version = "v1.0.0";
setWindowTitle(QString("q3d散点图示例 %1(作者:长沙红胖子 QQ:21497936 WX:15173255813 www.hpzwl.com").arg(version)); initControl();
} Q3dScatterWidget::~Q3dScatterWidget()
{
delete ui;
} void Q3dScatterWidget::setData(QList<QVector3D> listVector3D)
{
double xMin, xMax, yMin, yMax, zMin, zMax;
QScatterDataArray data;
for(int index = 0; index < listVector3D.size(); index++)
{
// 添加模拟数据
data << listVector3D.at(index);
// 计算范围
if(index == 0)
{
xMin = listVector3D.at(index).x();
xMax = listVector3D.at(index).x();
yMin = listVector3D.at(index).y();
yMax = listVector3D.at(index).y();
zMin = listVector3D.at(index).z();
zMax = listVector3D.at(index).z();
}else {
if(xMin > listVector3D.at(index).x() + 1e-8)
{
xMin = listVector3D.at(index).x();
}
if(xMax < listVector3D.at(index).x() - 1e-8)
{
xMax = listVector3D.at(index).x();
}
if(yMin > listVector3D.at(index).y() + 1e-8)
{
yMin = listVector3D.at(index).y();
}
if(yMax < listVector3D.at(index).y() - 1e-8)
{
yMax = listVector3D.at(index).y();
}
if(zMin > listVector3D.at(index).z() + 1e-8)
{
zMin = listVector3D.at(index).z();
}
if(zMax < listVector3D.at(index).z() - 1e-8)
{
zMax = listVector3D.at(index).z();
}
} }
// 添加数据(自动冲掉之前的数据)
_pScatter3DSeries->dataProxy()->addItems(data);
// 计算范围 x轴范围要大于等于y轴
if(xMax - xMin < yMax - yMin)
{
xMax = xMin + (yMax - yMin);
} _pQ3DScatter->axisX()->setRange(xMin, xMax);
_pQ3DScatter->axisY()->setRange(yMin, yMax);
_pQ3DScatter->axisZ()->setRange(zMin, zMax);
} void Q3dScatterWidget::initControl()
{
_pQ3DScatter = new Q3DScatter();
_pContainer = QWidget::createWindowContainer(_pQ3DScatter, this); // 设置轴文本
{
_pQ3DScatter->axisX()->setTitle("X");
_pQ3DScatter->axisY()->setTitle("Y");
_pQ3DScatter->axisZ()->setTitle("Z");
}
// 设置轴范围
{
// _pQ3DScatter->axisX()->setRange(0, 10);
// _pQ3DScatter->axisY()->setRange(0, 10);
// _pQ3DScatter->axisZ()->setRange(0, 10);
} // 生成一个曲线
_pScatter3DSeries = new QScatter3DSeries(_pQ3DScatter);
// 设置渲染平滑
_pScatter3DSeries->setMeshSmooth(true); // 视图添加该曲线
_pQ3DScatter->addSeries(_pScatter3DSeries); // 设置阴影质量
_pQ3DScatter->setShadowQuality(QAbstract3DGraph::ShadowQualitySoftLow);
// 设置视角
_pQ3DScatter->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetIsometricLeft);
// 设置子网格
_pQ3DScatter->activeTheme()->setGridEnabled(true); #if 1
// 添加模拟数据
QScatterDataArray data;
data << QVector3D(1, 1,1) << QVector3D(1, 1, 2) << QVector3D(1, 1, 3)
<< QVector3D(1, 2,1) << QVector3D(1, 2, 2) << QVector3D(1, 2, 3)
<< QVector3D(1, 3,1) << QVector3D(1, 3, 2) << QVector3D(1, 3, 3);
// 添加数据(自动冲掉之前的数据)
_pScatter3DSeries->dataProxy()->addItems(data);
#endif #if 1
// 模拟
QList<QVector3D> listVector3D;
#if 0
listVector3D << QVector3D(5, 1,1) << QVector3D(5, 1, 2) << QVector3D(5, 1, 3)
<< QVector3D(5, 2,1) << QVector3D(5, 2, 2) << QVector3D(5, 2, 3)
<< QVector3D(5, 3,1) << QVector3D(5, 3, 2) << QVector3D(5, 3, 3);
#else
listVector3D << QVector3D(1, 1,1) << QVector3D(1, 1, 2) << QVector3D(1, 1, 3)
<< QVector3D(1, 2,1) << QVector3D(1, 2, 2) << QVector3D(1, 2, 3)
<< QVector3D(1, 3,1) << QVector3D(1, 3, 2) << QVector3D(1, 3, 3);
#endif
// 添加数据
setData(listVector3D);
#endif
} void Q3dScatterWidget::resizeEvent(QResizeEvent *event)
{
if(_pContainer)
{
_pContainer->setGeometry(rect());
}
}
 

工程模板

  

 

入坑

入坑一:找不到Q3DScatter类

问题

  

原因

  有命名空间。

解决

using namespace QtDataVisualization;

Qt开发技术:Q3D图表开发笔记(一):Q3DScatter三维散点图介绍、Demo以及代码详解的更多相关文章

  1. Qt开发技术:QCharts(三)QCharts样条曲线图介绍、Demo以及代码详解

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  2. Qwt开发笔记(二):Qwt基础框架介绍、折线图介绍、折线图Demo以及代码详解

    前言   QWT开发笔记系列整理集合,这是目前使用最为广泛的Qt图表类(Qt的QWidget代码方向只有QtCharts,Qwt,QCustomPlot),使用多年,系统性的整理,本系列旨在系统解说并 ...

  3. ARM Cortex-M底层技术(2)—启动代码详解

    杂谈 工作了一天,脑袋比较乱.一直想把底层的知识写成一个系列,希望可以坚持下去.为什么要写底层的东西呢?首先,工作用到了这部分内容,最近和内部Flash打交道比较多,自然而然会接触到一些底层的东西:第 ...

  4. 8天掌握EF的Code First开发系列之3 管理数据库创建,填充种子数据以及LINQ操作详解

    本文出自8天掌握EF的Code First开发系列,经过自己的实践整理出来. 本篇目录 管理数据库创建 管理数据库连接 管理数据库初始化 填充种子数据 LINQ to Entities详解 什么是LI ...

  5. web标准 浏览器介绍 开发工具介绍 HTML介绍 HTML颜色介绍 规范 HTML结构详解 {前端之前端初识}

    前端之前端初识   前端初识 本节目录 一 web标准 二 浏览器介绍 三 开发工具介绍 四 HTML介绍 五 HTML颜色介绍 六 规范 七 HTML结构详解 一 web标准 web准备介绍: 1. ...

  6. 开发环境、测试环境、生产环境、UAT环境、仿真环境详解

    版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/WYX15011474269/article ...

  7. C#开发BIMFACE系列46 服务端API之离线数据包下载及结构详解

    BIMFACE二次开发系列目录     [已更新最新开发文章,点击查看详细] 在前一篇博客<C#开发BIMFACE系列45 服务端API之创建离线数据包>中通过调用接口成功的创建一个离线数 ...

  8. 【JAVAEE学习笔记】hibernate01:简介、搭建、配置文件详解、API详解和CRM练习:保存客户

    今日学习:hibernate是什么 一.hibernate是什么 框架是什么: 1.框架是用来提高开发效率的 2.封装了好了一些功能.我们需要使用这些功能时,调用即可.不需要再手动实现. 3.所以框架 ...

  9. [Java入门笔记] 面向对象编程基础(二):方法详解

    什么是方法? 简介 在上一篇的blog中,我们知道了方法是类中的一个组成部分,是类或对象的行为特征的抽象. 无论是从语法和功能上来看,方法都有点类似与函数.但是,方法与传统的函数还是有着不同之处: 在 ...

  10. [Spring学习笔记 1 ] Spring 简介,初步知识--Ioc容器详解 基本原理。

    一.Spring Ioc容器详解(1) 20131105 1.一切都是Bean Bean可是一个字符串或者是数字,一般是一些业务组件. 粒度一般比较粗. 2.Bean的名称 xml配置文件中,id属性 ...

随机推荐

  1. CF1557总结

    CF1557总结 Codeforces Round #737 (Div. 2) 先看了 A .意思是要把序列分成两个子序列,使得两序列各自平均值的和最小,输出最小值,要求 \(O(n)\) .想半天然 ...

  2. SSIS Package Version

    当 SSIS 首次出现时,有大量关于所有问题的笑话和帖子,以及每个人如何认为 DTS 更好,他们真的必须转换吗?多年来,我开始欣赏 SSIS.它是一个非常强大和有用的工具,可以做一些了不起的事情.当然 ...

  3. 实验:STM32-ARDUINO-ESP01采用AT指令,通过MQTT连接上ONENET

    1.硬件准备 要求:STM32支持Arduino. 2.程序逻辑结构 3.主流程状态机 4.测试数据抓图 5. 关键程序代码 unsigned char g_ArrTemp[1024]; int AT ...

  4. Linux 库的使用

    Linux 库的使用 -I头文件的路径-L动态库的路径   命名 使用 静态库 lib名字.a 静态库路径/lib名字.a 动态库 lib名字.so -L动态库路径 -l名字 编译 #静态编译 # g ...

  5. js 基础篇--保留字

    1.js把一些标识符拿出来用作自己的关键字.因此,就不能再在程序中把这些关键字用作标识符了: 1 break delete function return typeof 2 case do if sw ...

  6. PTA1002 写出这个数 (20 分)

    1002 写出这个数 (20 分) 读入一个正整数 n,计算其各位数字之和,用汉语拼音写出和的每一位数字. 输入格式: 每个测试输入包含 1 个测试用例,即给出自然数 n 的值.这里保证 n 小于 1 ...

  7. ABAP开发面向对象---类

    今日学习ABAP面向对象里面的类,关于构造,继承,实现. 踩坑点:类有抽象的方法,类本身也需要是抽象的,故需要在类申明里面加上ABSTRACT关键字 学习资料为B站翱翔云天老师的 1 CLASS zc ...

  8. 使用idea从零编写SpringCloud项目-Hystrix

    ps:Hystrix和Fegin里面使用的Hystrix,有些许区别.我理解的是Fegin.Hystrix主要是用于消费方在调用服务方接口时的异常处理,返回兜底数据等,而Hystrix则是消费方自己本 ...

  9. 导出数据库表以及备注为excel

    import com.alibaba.excel.annotation.ExcelProperty; import lombok.AllArgsConstructor; import lombok.D ...

  10. 11、jmeter配置元件--计数器

    前面学过csv和变量 csv里面的数据是固定的  如果里面的数据不够  线程要么就停止要么就需要重头再来 不太灵活 用到固定化的数据,比如说多少个用户等等 如果有一些是变动的 随着线程数增加   数据 ...