Qt之QtDataVisualization各三维图表的简单使用(含源码+注释)

一、图表操作示例图

1.图表选择示例

下图演示了通过下拉列表框切换三维图表的操作。
在这里插入图片描述

2.视角选项操作

下图演示了自动切换、通过spinBox控件切换和slider控件的缩放功能(三维图表自带有鼠标滚轮缩放功能)。
在这里插入图片描述

3.样式选项操作

下图演示了主题奇幻,系列样式切换,选择模式切换的效果
在这里插入图片描述

4.其他选项操作

下图演示了显示背景、显示网格、显示倒影和二维显示等功能。
在这里插入图片描述
二维显示截图
在这里插入图片描述

提示:不会使用Qt设计师设计界面的小伙伴点击这里

二、QtDataVisualization(个人理解)

  1. 使用前需要在pro文件中添加“QT += datavisualization”;
  2. 和QChart类似,导入头文件后还需通过“using namespace QtDataVisualization;”代码使用对应的命名空间;
  3. 其数据的存储方式也和QChart来说大同小异,有分装格式的,如:QWidget->Graph->Series->Proxy,QWidget为通过createWindowContainer()函数返回的容器对象,其中包含对应的图形对象(Graphi),三维图形也包括系列对象(series),并且系列对象中包含数据代理(Proxy,用于数据管理等),数据代理中也包括不同的数据对象,记住这个顺序,大体也是没问题的。

三、自定义槽函数的添加(UI界面)

在QChart文章中涉及到了槽函数添加的几种方式,现在再演示一种,操作流程如下:

  1. 按F4键,进入信号槽编辑模式;
  2. 选中按钮拖动会出现红色的关联线(需要连接哪个控件只需将关联线拖到到对应的控件上即可,本文为连接this,所以拖到了外边);
  3. 弹出配置连接后,选择信号,点击槽函数下方的编辑按钮,在信号槽界面添加自定义槽函数,然后确定,则成功绑定信号槽。
    在这里插入图片描述
    本文中和QChart一样也包含动态属性、按钮组,在此就不再介绍,想要了解的小伙伴点击这里QChart图表的简单使用,在该文的“部分源码讲解”内容中。

四、源码

(因为本文ui中包含动态属性,所以本文会留下ui代码,可复制粘贴到ui文件使用)

CMainWindow.h

#ifndef CMAINWINDOW_H
#define CMAINWINDOW_H

#include <QMainWindow>
#include <QAbstractButton>

// 导入数据可视化头文件
#include <QtDataVisualization>
//! 和QChart一样是要使用对应的命名空间
using namespace QtDataVisualization;

namespace Ui {
class CMainWindow;
}
//! 设置一个模板函数
template<class T>
void setSeriesStyle(T graphi, int index);

class CMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit CMainWindow(QWidget *parent = nullptr);
    ~CMainWindow();

    /**
     * @brief create3DBarGraph 创建三维柱状图
     * @return 返回三维柱状图指针
     */
    QAbstract3DGraph * create3DBarGraph();

    /**
     * @brief create3DScatterGraph 创建三维散点图
     * @return 返回散点图指针
     */
    QAbstract3DGraph * create3DScatterGraph();

    /**
     * @brief create3DSurfaceGraph 创建三维曲面图
     * @return 返回三维曲面图指针
     */
    QAbstract3DGraph * create3DSurfaceGraph();

    /**
     * @brief createValue3DAxis 创建值坐标轴
     * @param axisTitle 坐标轴标题
     * @param titleVisible 是否显示标题
     * @param min 坐标轴最小值
     * @param max 坐标轴最大值
     * @return 返回值坐标轴指针
     */
    QValue3DAxis *createValue3DAxis(QString axisTitle, bool titleVisible = true, float min = 0, float max = 100);

    /**
     * @brief createCategory3DAxis 创建文本坐标轴
     * @param axisTitle 坐标轴标题
     * @param titleVisible 是否显示坐标轴
     * @param labList 坐标轴标签
     * @return 返回值坐标轴指针
     */
    QCategory3DAxis *createCategory3DAxis(QString axisTitle, bool titleVisible = true, QStringList labList = QStringList());

    // QObject interface
protected:
    /**
     * @brief timerEvent 定时器时间
     * @param event 定时器对象
     */
    void timerEvent(QTimerEvent *event);

private slots:
    /**
     * @brief on_angleValueChange 视角改变槽函数
     * @param val 角度值
     */
    void on_angleValueChange(int val);

    /**
     * @brief on_otherOptionGroup_buttonClicked 其他选项按钮组槽函数
     * @param button 点击的按钮指针
     */
    void on_otherOptionGroup_buttonClicked(QAbstractButton *button);

    /**
     * @brief on_seriesStyleComboBox_currentIndexChanged 系列样式设置槽函数
     * @param index 样式索引值
     */
    void on_seriesStyleComboBox_currentIndexChanged(int index);

    /**
     * @brief on_themeComboBox_currentIndexChanged 主题选择槽函数
     * @param index 主题索引值
     */
    void on_themeComboBox_currentIndexChanged(int index);

    /**
     * @brief on_selectModeComboBox_currentIndexChanged 选择模式槽函数
     * @param index 选择模式索引值
     */
    void on_selectModeComboBox_currentIndexChanged(int index);

    /**
     * @brief on_scaleSlider_sliderMoved 缩放功能槽函数
     * @param position 缩放值
     */
    void on_scaleSlider_sliderMoved(int position);

    /**
     * @brief on_autoSwitchAngleBtn_clicked 自动切换视角按钮槽函数
     * @param checked 按钮选中状态
     */
    void on_autoSwitchAngleBtn_clicked(bool checked);

    /**
     * @brief on_typeComboBox_currentIndexChanged 图表类型选选择槽函数
     * @param index 类型索引值
     */
    void on_typeComboBox_currentIndexChanged(int index);

private:
    Ui::CMainWindow             *ui;            // ui对象指针

    QList<QAbstract3DGraph *>   m_graphLsit;    // 图表容器指针

    int                         m_timer;        // 定时器对象

};

#endif // CMAINWINDOW_H

CMainWindow.cpp

#include "CMainWindow.h"
#include "ui_CMainWindow.h"
#include <QtDebug>

CMainWindow::CMainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::CMainWindow)
{
    ui->setupUi(this);
    // 设置标题
    this->setWindowTitle("三维图形的简单使用");

    // 创建三维柱状图
    m_graphLsit.append(create3DBarGraph());
    // 创建三维散点图
    m_graphLsit.append(create3DScatterGraph());
    // 创建三维曲面图
    m_graphLsit.append(create3DSurfaceGraph());

    // 重置随机数种子
    srand(QDateTime::currentSecsSinceEpoch() % 1000000);

//    ui->otherOptionGroup->setExclusive(false);  // 设置按钮组可多选(ui界面已设置)
}

CMainWindow::~CMainWindow()
{
    // 遍历删除图表对象
    for(int index = m_graphLsit.count() - 1; index != -1; --index)
    {
        // 释放图表
        delete m_graphLsit.at(index);
    }
    // 删除ui对象
    delete ui;
}

QAbstract3DGraph *CMainWindow::create3DBarGraph()
{
    // 创建三维柱状图对象
    Q3DBars *bars = new Q3DBars;
    // 创建三维柱状图容器
    QWidget *container = QWidget::createWindowContainer(bars);
    // 将当前容器添加到栈窗口对象中,并设置容器为栈窗口当前窗口
    ui->stackedWidget->addWidget(container);
    ui->stackedWidget->setCurrentWidget(container);


    // 创建三维柱状图坐标轴对象
    bars->setValueAxis(createValue3DAxis("Value Axis", true, 0, 10));
    // 创建坐标轴标签容器并添加到坐标轴中
    // 列坐标轴
    QStringList colLabs;
    colLabs << "Column1" << "Column2" << "Column3";
    bars->setColumnAxis(createCategory3DAxis("Column Category Axis", true, colLabs));
    // 行坐标轴
    QStringList rowLabs;
    rowLabs << "Row1" << "Row2" << "Row3";
    bars->setRowAxis(createCategory3DAxis("Row Category Axis", true, rowLabs));


    // 创建三维柱状图系列对象
    QBar3DSeries *series = new QBar3DSeries;
    // 将系列对象添加到三维柱状图对象中
    bars->addSeries(series);

    // 创建三维柱状图数据容器
    QBarDataArray *array = new QBarDataArray;
    // 循环创建数据
    for(int index = 0; index != 3; ++index)
    {
        // 创建柱状图行数据容器
        QBarDataRow *dataRow = new QBarDataRow;
        // 使用随机数添加数据
        *dataRow << rand() % 10 << rand() % 10 << rand() % 10 << rand() % 10 << rand() % 10;
        // 将行数据添加到array对象中
        array->append(dataRow);
    }
    // 将创建的数据添加到系列对象中(当指针容器指针不同时,将重置添加)
    series->dataProxy()->resetArray(array);

    // 设置动态属性(类型,作用为在设置系列样式槽函数中区分)
    bars->setProperty("Type", 0);

    // 返回三维柱状图对象
    return bars;
}

QAbstract3DGraph *CMainWindow::create3DScatterGraph()
{
    // 创建三维散点图对象
    Q3DScatter *scatter = new Q3DScatter;
    // 创建三维散点图容器
    QWidget *container = QWidget::createWindowContainer(scatter);
    // 将当前容器添加到栈窗口对象中
    ui->stackedWidget->addWidget(container);

    //! 创建三维散点图的坐标轴
    //! 因为是三维散点图,所以包括X、Y、Z三个方向的坐标轴(并且三个坐标轴类型都为值坐标轴哦)
    // 创建X、Y、Z轴并添加
    scatter->setAxisX(createValue3DAxis("X Axis"));
    scatter->setAxisY(createValue3DAxis("Y Axis"));
    scatter->setAxisZ(createValue3DAxis("Z Axis"));


    // 创建三维散点图的系列对象
    QScatter3DSeries *series = new QScatter3DSeries;
    // 将系列对象添加到三维散点图对象中
    scatter->addSeries(series);

    // 创建三维散点图的数据容器
    QScatterDataArray array;
    // 循环添加数据
    for(int index = 0; index != 30; ++index)
    {
        // 使用随机数添加点
        array.append(QVector3D(rand() % 100, rand() % 100, rand() % 100));
    }
    // 将创建的数据添加到系列对象中(做追加数组的操作)
    series->dataProxy()->addItems(array);

    // 设置动态属性(类型,作用为在设置系列样式槽函数中区分)
    scatter->setProperty("Type", 1);

    // 返回三维散点图指针
    return scatter;
}

QAbstract3DGraph *CMainWindow::create3DSurfaceGraph()
{
    // 创建三维曲面图对象
    Q3DSurface *surface = new Q3DSurface;
    // 创建三维曲面图容器
    QWidget *container = QWidget::createWindowContainer(surface);
    // 将容器添加到栈窗口中
    ui->stackedWidget->addWidget(container);


    //! 创建三维散点图的坐标轴
    //! 因为是三维散点图,所以包括X、Y、Z三个方向的坐标轴(并且三个坐标轴类型都为值坐标轴哦)
    // 创建X、Y、Z轴并添加
    surface->setAxisX(createValue3DAxis("X Axis"));
    surface->setAxisY(createValue3DAxis("Y Axis"));
    surface->setAxisZ(createValue3DAxis("Z Axis"));


    // 创建三维曲面图系列对象
    QSurface3DSeries *series = new QSurface3DSeries;
    // 将系列添加到三维曲面图中
    surface->addSeries(series);

    // 创建三维曲面图数据容器
    QSurfaceDataArray *array = new QSurfaceDataArray;
    // 创建三维曲面图数据
    for(int index = 0; index != 5; ++index)
    {
        // 创建三维曲面图行数据容器
        QSurfaceDataRow *dataRow = new QSurfaceDataRow;
        // 遍历添加数据到行容器
        for(int valIdx = 0; valIdx != 3; ++valIdx)
        {
            // 随机数添加数据
            dataRow->append(QVector3D(rand() % 100, rand() % 100, rand() % 100));
        }
        // 将行容器添加到array中
        array->append(dataRow);
    }
    // 将数据添加到系列对象中
    series->dataProxy()->resetArray(array);

    //! 因为曲面图是面,所以切换系列类型没有变化
    //! 若要设置面的样式可像下方一样调用setDrawMode函数
    //! surface->seriesList()[0]->setDrawMode(QSurface3DSeries::DrawFlag(vlaue));
    //! value:枚举值 其中枚举值如下
    //! QSurface3DSeries::DrawWireframe 仅绘制网格。
    //! QSurface3DSeries::DrawSurface   仅绘制曲面。
    //! QSurface3DSeries::DrawSurfaceAndWireframe    绘制曲面和栅格。

    //! 设置动态属性(类型,作用为在设置系列样式槽函数中区分)
    surface->setProperty("Type", -1);


    // 返回三维曲面图对象
    return surface;

}

QValue3DAxis *CMainWindow::createValue3DAxis(QString axisTitle, bool titleVisible, float min, float max)
{
    // 创建值坐标轴对象
    QValue3DAxis *axis = new QValue3DAxis;
    axis->setTitle(axisTitle);  // 设置坐标轴标题
    axis->setTitleVisible(titleVisible); // 设置标题是否显示
    axis->setRange(min, max);   // 设置坐标轴取值范围
    // 返回坐标轴对象
    return axis;
}

QCategory3DAxis *CMainWindow::createCategory3DAxis(QString axisTitle, bool titleVisible, QStringList labList)
{
    // 创建文本坐标轴对象
    QCategory3DAxis *axis = new QCategory3DAxis;
    axis->setTitle(axisTitle);  // 设置坐标轴标题
    axis->setTitleVisible(titleVisible); // 设置标题是否显示
    axis->setLabels(labList);   // 设置坐标轴标签
    // 返回坐标轴对象
    return axis;

}

void CMainWindow::on_angleValueChange(int val)
{
    // 拿到信号发送者
    QSpinBox *spinBox = dynamic_cast<QSpinBox *>(sender());

    // 若当前为定时改变视角则不设置活动摄像角度,并将动态属性值设置为false
    if(spinBox->property("RotationFlag").toBool())
    {
        spinBox->setProperty("RotationFlag", false);
        return;
    }

    // 拿到视角类型
    int type = spinBox->property("DirectionType").toInt();

    // 判断当前方向类型,并将角度赋到对应位置
    if(0 == type)
    {
        // 遍历设置所有三维图的X轴视角
        foreach(QAbstract3DGraph *graph, m_graphLsit)
        {
            // 获取图表的视图->活动摄像头->设置角度
            graph->scene()->activeCamera()->setXRotation(val);
        }
    }
    else if(1 == type)
    {
        // 遍历设置所有三维图的Y轴视角
        foreach(QAbstract3DGraph *graph, m_graphLsit)
        {
            // 获取图表的视图->活动摄像头->设置角度
            graph->scene()->activeCamera()->setYRotation(val);
        }
    }

}

void CMainWindow::on_otherOptionGroup_buttonClicked(QAbstractButton *button)
{
    // 将按钮对象转为复选框对象
    QCheckBox *curBox = dynamic_cast<QCheckBox *>(button);
    // 获取当前按钮的类型
    int type = curBox->property("OptionType").toInt();
    // 获取按钮选择状态
    bool checkedStatus = curBox->isChecked();
    switch (type)
    {
    case 0:
    {
        // 循环设置图表状态
        foreach(QAbstract3DGraph *graph, m_graphLsit)
        {
            // 设置背景可用
            graph->activeTheme()->setBackgroundEnabled(checkedStatus);
            // 标签可用
            graph->activeTheme()->setLabelBackgroundEnabled(checkedStatus);
        }
        break;
    }
    case 1:
    {
        // 循环设置图表状态
        foreach(QAbstract3DGraph *graph, m_graphLsit)
        {
            // 设置显示网格
            graph->activeTheme()->setGridEnabled(checkedStatus);
        }
        break;
    }
    case 2:
    {
        // 循环设置图表状态
        foreach(QAbstract3DGraph *graph, m_graphLsit)
        {
            // 设置显示倒影
            graph->setReflection(checkedStatus);
        }
        break;
    }
    case 3:
    {
        // 循环设置图表状态
        foreach(QAbstract3DGraph *graph, m_graphLsit)
        {
            // 设置正交投影显示(偏二维)
            graph->setOrthoProjection(checkedStatus);
        }
        break;
    }
    default:
        break;
    }
}

void CMainWindow::timerEvent(QTimerEvent *event)
{
    Q_UNUSED(event);
    // 创建当前摄像头对象
    Q3DCamera *curCamera;
    // 循环设置相机视角
    foreach(QAbstract3DGraph *graph, m_graphLsit)
    {
        // 获取当前视图视角
        curCamera = graph->scene()->activeCamera();
        // 获取当前视角值
        int curCameraPreset = curCamera->cameraPreset();
        // 判断获取下一是视角值
        int cameraPreset = curCameraPreset == 21? 1: curCameraPreset + 1;
        // 设置相机视角
        curCamera->setCameraPreset(Q3DCamera::CameraPreset(cameraPreset));
    }

    // 设置水平视角控件值
    ui->horAngleSpinBox->setValue(curCamera->xRotation());
    // 设置水平动态属性
    ui->horAngleSpinBox->setProperty("RotationFlag", true);
    // 设置垂直视角控件值
    ui->verAngleSpinBox->setValue(curCamera->yRotation());
    // 设置水平动态属性
    ui->verAngleSpinBox->setProperty("RotationFlag", true);
}

void CMainWindow::on_seriesStyleComboBox_currentIndexChanged(int index)
{
    // 循环设置图表系列状态
    foreach(QAbstract3DGraph *graph, m_graphLsit)
    {
        int type = graph->property("Type").toInt();
        // 获取当前图表类型
        switch (type)
        {
        case 0:
        {
            // 调用样式模板函数
            setSeriesStyle(dynamic_cast<Q3DBars *>(graph), index);
            break;
        }
        case 1:
        {
            // 调用样式模板函数
            setSeriesStyle(dynamic_cast<Q3DScatter *>(graph), index);
            break;
        }
        default:
            break;
        }
    }
}

void CMainWindow::on_themeComboBox_currentIndexChanged(int index)
{
    // 循环设置图表主题
    foreach(QAbstract3DGraph *graph, m_graphLsit)
    {
        graph->activeTheme()->setType(Q3DTheme::Theme(index));
    }
}

void CMainWindow::on_selectModeComboBox_currentIndexChanged(int index)
{
    // 设置柱状图的选择模式
    m_graphLsit.first()->setSelectionMode(QAbstract3DGraph::SelectionFlag(index));
}

void CMainWindow::on_scaleSlider_sliderMoved(int position)
{
    // 循环设置图表缩放
    foreach(QAbstract3DGraph *graph, m_graphLsit)
    {
        graph->scene()->activeCamera()->setZoomLevel(position);
    }
}

void CMainWindow::on_autoSwitchAngleBtn_clicked(bool checked)
{
    // 根据状态做出相应操作
    if(checked)
    {
        // 改变按钮文本
        ui->autoSwitchAngleBtn->setText("停止");
        // 启动定时器
        m_timer = startTimer(750);
    }
    else
    {
        // 改变按钮文本
        ui->autoSwitchAngleBtn->setText("开始");
        // 终止定时器
        killTimer(m_timer);
    }
}

template<class T>
void setSeriesStyle(T graphi, int index)
{
    // 循环设置图表样式
    foreach(QAbstract3DSeries *series, graphi->seriesList())
    {
        //! 设置样式
        //! 索引值加1是防止设置值为0的Mesh,未作出对应操作设置该值的样式会导致程序崩溃
        //! 帮助中这样形容(翻译):用户定义网格,通过QAbstract3DSeries::userDefinedMesh属性设置。
        series->setMesh(QAbstract3DSeries::Mesh(index + 1));
    }
}

void CMainWindow::on_typeComboBox_currentIndexChanged(int index)
{
    // 设置当前显示的图表
    ui->stackedWidget->setCurrentIndex(index);

    //! 判断选择模式禁用,仅在三维柱状图下可用
    //! 因为在测试时发现本文中的三维散点图仅支持“无”和单项选择模式,三维曲面图不支持选择模式
    ui->selectModeComboBox->setEnabled(0 == index);

    //! 判断显示倒影禁用,仅在三维柱状图下可用
    //! 因为在测试时发现本文中的三维散点图、三维曲面图并无倒影显示
    ui->showReflectionCheckBox->setEnabled(0 == index);

    //! 判断设置系列样式禁用
    //! 三维曲面图设置Mesh无效,则禁用
    ui->seriesStyleComboBox->setEnabled(2 != index);

}

CMainWindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>CMainWindow</class>
 <widget class="QMainWindow" name="CMainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>720</width>
    <height>466</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>CMainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,1">
    <property name="spacing">
     <number>0</number>
    </property>
    <property name="leftMargin">
     <number>0</number>
    </property>
    <property name="topMargin">
     <number>0</number>
    </property>
    <property name="rightMargin">
     <number>0</number>
    </property>
    <property name="bottomMargin">
     <number>0</number>
    </property>
    <item>
     <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,1,1,1">
      <property name="spacing">
       <number>10</number>
      </property>
      <property name="leftMargin">
       <number>7</number>
      </property>
      <property name="topMargin">
       <number>5</number>
      </property>
      <property name="rightMargin">
       <number>10</number>
      </property>
      <property name="bottomMargin">
       <number>5</number>
      </property>
      <item>
       <layout class="QHBoxLayout" name="horizontalLayout_2">
        <property name="leftMargin">
         <number>5</number>
        </property>
        <property name="topMargin">
         <number>5</number>
        </property>
        <property name="rightMargin">
         <number>5</number>
        </property>
        <property name="bottomMargin">
         <number>5</number>
        </property>
        <item>
         <widget class="QLabel" name="label">
          <property name="text">
           <string>三维(图)类型:</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QComboBox" name="typeComboBox">
          <item>
           <property name="text">
            <string>三维柱状图</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>三维散点图</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>三维曲面图</string>
           </property>
          </item>
         </widget>
        </item>
       </layout>
      </item>
      <item>
       <widget class="QGroupBox" name="groupBox">
        <property name="title">
         <string>视角选项</string>
        </property>
        <layout class="QGridLayout" name="gridLayout">
         <property name="leftMargin">
          <number>5</number>
         </property>
         <property name="topMargin">
          <number>5</number>
         </property>
         <property name="rightMargin">
          <number>5</number>
         </property>
         <property name="bottomMargin">
          <number>5</number>
         </property>
         <property name="verticalSpacing">
          <number>5</number>
         </property>
         <item row="0" column="0">
          <widget class="QLabel" name="label_2">
           <property name="text">
            <string>自动切换视角:</string>
           </property>
          </widget>
         </item>
         <item row="0" column="1">
          <widget class="QPushButton" name="autoSwitchAngleBtn">
           <property name="maximumSize">
            <size>
             <width>100</width>
             <height>16777215</height>
            </size>
           </property>
           <property name="text">
            <string>开始</string>
           </property>
           <property name="checkable">
            <bool>true</bool>
           </property>
          </widget>
         </item>
         <item row="1" column="0" colspan="2">
          <layout class="QHBoxLayout" name="horizontalLayout">
           <property name="spacing">
            <number>0</number>
           </property>
           <item>
            <widget class="QLabel" name="label_3">
             <property name="text">
              <string>水平视角:</string>
             </property>
            </widget>
           </item>
           <item>
            <widget class="QSpinBox" name="horAngleSpinBox">
             <property name="suffix">
              <string>°</string>
             </property>
             <property name="prefix">
              <string/>
             </property>
             <property name="minimum">
              <number>-180</number>
             </property>
             <property name="maximum">
              <number>180</number>
             </property>
             <property name="singleStep">
              <number>5</number>
             </property>
             <property name="DirectionType" stdset="0">
              <number>0</number>
             </property>
            </widget>
           </item>
           <item>
            <spacer name="horizontalSpacer">
             <property name="orientation">
              <enum>Qt::Horizontal</enum>
             </property>
             <property name="sizeHint" stdset="0">
              <size>
               <width>40</width>
               <height>20</height>
              </size>
             </property>
            </spacer>
           </item>
           <item>
            <widget class="QLabel" name="label_4">
             <property name="text">
              <string>垂直视角:</string>
             </property>
            </widget>
           </item>
           <item>
            <widget class="QSpinBox" name="verAngleSpinBox">
             <property name="suffix">
              <string>°</string>
             </property>
             <property name="prefix">
              <string/>
             </property>
             <property name="maximum">
              <number>90</number>
             </property>
             <property name="singleStep">
              <number>5</number>
             </property>
             <property name="DirectionType" stdset="0">
              <number>1</number>
             </property>
            </widget>
           </item>
          </layout>
         </item>
         <item row="2" column="0">
          <widget class="QLabel" name="label_5">
           <property name="text">
            <string>缩放:</string>
           </property>
          </widget>
         </item>
         <item row="2" column="1">
          <widget class="QSlider" name="scaleSlider">
           <property name="minimum">
            <number>10</number>
           </property>
           <property name="maximum">
            <number>500</number>
           </property>
           <property name="value">
            <number>100</number>
           </property>
           <property name="orientation">
            <enum>Qt::Horizontal</enum>
           </property>
          </widget>
         </item>
        </layout>
       </widget>
      </item>
      <item>
       <widget class="QGroupBox" name="groupBox_2">
        <property name="title">
         <string>样式选项</string>
        </property>
        <layout class="QFormLayout" name="formLayout">
         <property name="horizontalSpacing">
          <number>0</number>
         </property>
         <property name="verticalSpacing">
          <number>10</number>
         </property>
         <property name="leftMargin">
          <number>5</number>
         </property>
         <property name="topMargin">
          <number>5</number>
         </property>
         <property name="rightMargin">
          <number>5</number>
         </property>
         <property name="bottomMargin">
          <number>5</number>
         </property>
         <item row="0" column="0">
          <widget class="QLabel" name="label_6">
           <property name="text">
            <string>主题:</string>
           </property>
          </widget>
         </item>
         <item row="0" column="1">
          <widget class="QComboBox" name="themeComboBox">
           <item>
            <property name="text">
             <string>ThemeQt</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>ThemePrimaryColors</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>ThemeDigia</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>ThemeStoneMoss</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>ThemeArmyBlue</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>ThemeRetro</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>ThemeEbony</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>ThemeIsabelle</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>ThemeUserDefined</string>
            </property>
           </item>
          </widget>
         </item>
         <item row="1" column="0">
          <widget class="QLabel" name="label_7">
           <property name="text">
            <string>系列样式:</string>
           </property>
          </widget>
         </item>
         <item row="1" column="1">
          <widget class="QComboBox" name="seriesStyleComboBox">
           <item>
            <property name="text">
             <string>MeshBar</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>MeshCube</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>MeshPyramid</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>MeshCone</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>MeshCylinder</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>MeshBevelBar</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>MeshBevelCube</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>MeshSphere</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>MeshMinimal</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>MeshArrow</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>MeshPoint</string>
            </property>
           </item>
          </widget>
         </item>
         <item row="2" column="0">
          <widget class="QLabel" name="label_8">
           <property name="text">
            <string>选择模式:</string>
           </property>
          </widget>
         </item>
         <item row="2" column="1">
          <widget class="QComboBox" name="selectModeComboBox">
           <item>
            <property name="text">
             <string>SelectionNone</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>SelectionItem</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>SelectionRow</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>SelectionItemAndRow</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>SelectionColumn</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>SelectionItemAndColumn</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>SelectionRowAndColumn</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>SelectionItemRowAndColumn</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>SelectionSlice</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>SelectionMultiSeries</string>
            </property>
           </item>
          </widget>
         </item>
        </layout>
       </widget>
      </item>
      <item>
       <widget class="QGroupBox" name="groupBox_3">
        <property name="title">
         <string>其他选项</string>
        </property>
        <layout class="QGridLayout" name="gridLayout_3">
         <property name="leftMargin">
          <number>5</number>
         </property>
         <property name="topMargin">
          <number>5</number>
         </property>
         <property name="rightMargin">
          <number>5</number>
         </property>
         <property name="bottomMargin">
          <number>5</number>
         </property>
         <property name="spacing">
          <number>0</number>
         </property>
         <item row="0" column="0">
          <widget class="QCheckBox" name="showBgCheckBox">
           <property name="text">
            <string>显示背景</string>
           </property>
           <property name="checked">
            <bool>true</bool>
           </property>
           <property name="OptionType" stdset="0">
            <number>0</number>
           </property>
           <attribute name="buttonGroup">
            <string notr="true">otherOptionGroup</string>
           </attribute>
          </widget>
         </item>
         <item row="0" column="1">
          <widget class="QCheckBox" name="showGridCheckBox">
           <property name="text">
            <string>显示网格</string>
           </property>
           <property name="checked">
            <bool>true</bool>
           </property>
           <property name="OptionType" stdset="0">
            <number>1</number>
           </property>
           <attribute name="buttonGroup">
            <string notr="true">otherOptionGroup</string>
           </attribute>
          </widget>
         </item>
         <item row="1" column="0">
          <widget class="QCheckBox" name="showReflectionCheckBox">
           <property name="text">
            <string>显示倒影</string>
           </property>
           <property name="OptionType" stdset="0">
            <number>2</number>
           </property>
           <attribute name="buttonGroup">
            <string notr="true">otherOptionGroup</string>
           </attribute>
          </widget>
         </item>
         <item row="1" column="1">
          <widget class="QCheckBox" name="twoDimenCheckBox">
           <property name="text">
            <string>二维显示</string>
           </property>
           <property name="OptionType" stdset="0">
            <number>3</number>
           </property>
           <attribute name="buttonGroup">
            <string notr="true">otherOptionGroup</string>
           </attribute>
          </widget>
         </item>
        </layout>
       </widget>
      </item>
     </layout>
    </item>
    <item>
     <widget class="QStackedWidget" name="stackedWidget"/>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>720</width>
     <height>23</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections>
  <connection>
   <sender>horAngleSpinBox</sender>
   <signal>valueChanged(int)</signal>
   <receiver>CMainWindow</receiver>
   <slot>on_angleValueChange(int)</slot>
   <hints>
    <hint type="sourcelabel">
     <x>110</x>
     <y>130</y>
    </hint>
    <hint type="destinationlabel">
     <x>-83</x>
     <y>239</y>
    </hint>
   </hints>
  </connection>
  <connection>
   <sender>verAngleSpinBox</sender>
   <signal>valueChanged(int)</signal>
   <receiver>CMainWindow</receiver>
   <slot>on_angleValueChange(int)</slot>
   <hints>
    <hint type="sourcelabel">
     <x>273</x>
     <y>131</y>
    </hint>
    <hint type="destinationlabel">
     <x>-157</x>
     <y>269</y>
    </hint>
   </hints>
  </connection>
 </connections>
 <slots>
  <slot>on_angleValueChange(int)</slot>
 </slots>
 <buttongroups>
  <buttongroup name="otherOptionGroup">
   <property name="exclusive">
    <bool>false</bool>
   </property>
  </buttongroup>
 </buttongroups>
</ui>

main.cpp

#include "CMainWindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    CMainWindow w;
    w.show();

    return a.exec();
}

总结

由于三图存在于同一个简单的Demo中,功能不是很完善,和QChart一样,各个图表的选项独立最好(就是说每次点击按钮只改变当前图表的属性),有兴趣的伙伴可以优化此功能; 在开发过程中,多多少少还是会有碰壁,另外其实还有许多BUG都没有正面处理,原本想多种函数通用实现样式,最后发现样式多多少少有些差别,不得不限制某些控件在不同图表中的状态;除此之外还有很多值得我们去发掘的功能和BUG,学无止境,冲鸭😆。
现在也是很晚了,那就休息了,晚安吧😁。

相关文章

Qt之QChart各个图表的简单使用(含源码+注释)

友情提示——哪里看不懂可私哦,让我们一起互相进步吧
(创作不易,请留下一个免费的赞叭 谢谢 ^o^/)

注:文章为作者编程过程中所遇到的问题和总结,内容仅供参考,若有错误欢迎指出。
注:如有侵权,请联系作者删除

QtDataVisualizationQt中的一个模块,用于可视化数据,包括3D图形和2D图形。其中,三维散点图是其中的一种类型,可以用于展示三维数据中的散点分布情况。 使用QtDataVisualization绘制三维散点图的步骤如下: 1. 创建一个Q3DScatter对象,用于展示三维散点图。 2. 创建一个QScatterDataArray对象,用于存储散点数据。 3. 将散点数据添加到QScatterDataArray对象中。 4. 创建一个QScatterDataProxy对象,用于将散点数据与Q3DScatter对象关联。 5. 设置Q3DScatter对象的坐标轴范围、主题、标题等属性。 6. 将Q3DScatter对象添加到QWidget中进行展示。 下面是一个简单的示例代码,用于展示如何使用QtDataVisualization绘制三维散点图: ``` #include <QtWidgets/QApplication> #include <QtDataVisualization/Q3DScatter> #include <QtDataVisualization/QScatterDataProxy> #include <QtDataVisualization/QScatterDataArray> using namespace QtDataVisualization; int main(int argc, char *argv[]) { QApplication a(argc, argv); // 创建一个Q3DScatter对象 Q3DScatter *scatter = new Q3DScatter(); // 创建一个QScatterDataArray对象 QScatterDataArray dataArray; // 添加散点数据到QScatterDataArray对象中 for (float x = -10.0f; x <= 10.0f; x += 0.5f) { for (float y = -10.0f; y <= 10.0f; y += 0.5f) { for (float z = -10.0f; z <= 10.0f; z += 0.5f) { dataArray << QVector3D(x, y, z); } } } // 创建一个QScatterDataProxy对象,并将散点数据与Q3DScatter对象关联 QScatterDataProxy *proxy = new QScatterDataProxy(); proxy->addItems(dataArray); scatter->addSeries(proxy); // 设置Q3DScatter对象的坐标轴范围、主题、标题等属性 scatter->activeTheme()->setType(Q3DTheme::ThemeEbony); scatter->axisX()->setTitle("X Axis Title"); scatter->axisY()->setTitle("Y Axis Title"); scatter->axisZ()->setTitle("Z Axis Title"); // 将Q3DScatter对象添加到QWidget中进行展示 QWidget *container = QWidget::createWindowContainer(scatter); container->setMinimumSize(800, 600); container->setWindowTitle("QtDataVisualization - 3D Scatter"); container->show(); return a.exec(); } ``` 运行该示例代码,可以得到一个包了大量散点的三维散点图,如下图所示: ![QtDataVisualization - 3D Scatter](https://blog.csdn.net/qq_41453285/article/details/107261516)
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lw向北.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值