前言

  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. HCIA-ICT实战基础08-访问控制列表ACL原理与配置

    HCIA-ICT实战基础-访问控制列表ACL原理与配置 目录 ACL技术概述 ACL的基本概念及其工作原理 ACL的基础配置及应用 ACL技术概述 技术背景: 需要一个工具实现流量过滤 ACL是由一系 ...

  2. CCIE DC Multicast Part 1.

    Hi Guys! As we all wait anxiously for the training vendors to release Rack Rentals (Come on guys! At ...

  3. 【BOOK】动态渲染页面爬取--Selenium库

    动态渲染页面爬取 JavaScript动态渲染 其中一种方式是Ajax请求,通过直接分析Ajax再用requests来实现数据爬取 另外一种方式是模拟浏览器运行 一. Selenium库 Seleni ...

  4. 什么是spring框架

    一bai.概念:1. spring是开源的轻量级框架2 spring核心主要两部分:(1)aop:面向切面编程,扩展功能不是修改源代码实现(2)ioc:控制反转,- 比如有一个类,在类里面有方法(不是 ...

  5. ansiable学习

    ansiable是用来做什么的? Ansible是一个配置管理和配置工具,是运维开发人员的批操作利器. ansiable是怎样实现高效的? 在一台机器上配置好模板,通过ssh在其他机器上按照模板执行. ...

  6. AI基本知识

    一.什么是flops 对flops有疑惑,首先得先捋清这个概念: FLOPS:注意全大写,是floating point operations per second的缩写,意指每秒浮点运算次数,理解为 ...

  7. uniapp 全局注册组件注意事项

    标准 根目录components  文件夹下建立 组件文件名文件夹 然后组件 autoscan  打开 别的用不到不写 全局使用 备注 因为不是vuecli 项目 只在H5 端生效  在app  上生 ...

  8. AutoCAD2018_64bit

    「AutoCAD_2018_Simplified_...hinese_Win_64bit」https://www.aliyundrive.com/s/eiLscbxkMui 点击链接保存,或者复制本段 ...

  9. python-文件内容操作

    1.按文件中数据的组织形式把文件分为文本文件和二进制文件两类. 文本文件:文本文件存储的是常规字符串,由若干文本行组成,通常每行以换行符'\n'结尾.常规字符串是指记事本或其他文本编辑器能正常显示.编 ...

  10. vue-封装组件-结合vant实现点击按钮弹出泡泡(Popover)事件控制多个泡泡出现时,弹出对应的泡泡

    <template> <div class="sale-share-box"> <span class="sale-share-btn&qu ...