Qt 三维柱状图 Q3DBar 和 三维条形图中的数据序列 QBar3DSeries

(一) 使用 Q3DBars 图形类和 QBar3DSeries 序列类可以绘制三维柱状图

窗口右侧是用 Q3DBars 和 QBar3DSeries 绘制的三维柱状图,这个图只有一个QBar3DSeries序列,数据是按行存储的,可以有多行。水平方向是行坐标轴和列坐标轴,使用OCategory3DAxis 坐标轴类;垂直方向是数值坐标轴,使用 QValue3DAxis 坐标轴类。在图上点击一个棒柱时,可以在图上显示其行标签、列标签和数值,状态栏上还会显示其行编号、列编号和数值 。无须额外编程或设置,在图上按住鼠标右键并上下左右拖动鼠标可以进行水平和垂直方向的旋转,滚动鼠标滚轮可以进行缩放。 窗口工具栏上的按钮用于修改棒柱的基本颜色,修改选中棒柱的数值,添加、插入或删除行等。 窗口左侧是操作面板,分为多个分组框。

  • "旋转和平移"分组框。可以选择预设的三维图观察视角,可以通过 QSlider 组件进行水平旋转、垂直旋转和缩放。
  • 分组框里的4个方向按钮用于使三维柱状图在4个方向上平移,中间的按钮用于复位视角。
  • "图形总体"分组框。用于设置三维图形的主题、标签字体大小、棒柱选择模式,以及设置三维图形的各种元素的可见性和显示效果等。
  • "序列设置"分组框。设置序列的一些属性,如棒柱的样式、光滑效果等。

效果图:

(二) 3D部件创建及添加到窗口

1 添加三维图Q3DBars 三维图的容器QWidget和三维条形图中的数据序列QBar3DSeries

cpp 复制代码
private:
    QWidget* graphContainer;        //三维图的容器
    Q3DBars* graph3D;               //三维图
    QBar3DSeries* series;           //三维条形图中的数据序列

2 初始化 3D部件并添加到窗口

cpp 复制代码
void mainwindow::iniGraph3D()
{
    graph3D = new Q3DBars();            //创建三维图
    graphContainer = QWidget::createWindowContainer(graph3D, this);//Q3DBars继承自QWindow
    graph3D->scene()->activeCamera()    //设置视角
                ->setCameraPreset(Q3DCamera::CameraPresetFrontHigh); 

    //设置 Z坐标轴
    QValue3DAxis* axisV = new QValue3DAxis; //数值坐标
    axisV->setTitle(QString::fromLocal8Bit("销量"));
    axisV->setTitleVisible(true);
    axisV->setLabelFormat("%d");
    graph3D->setValueAxis(axisV);  			 //设置数值坐标轴

    //设置 X坐标轴
    QCategory3DAxis* axisRow = new QCategory3DAxis;
    axisRow->setTitle("row axis");
    axisRow->setTitleVisible(true);
    graph3D->setRowAxis(axisRow);  			 //设置行坐标轴

    //设置 Y坐标轴
    QCategory3DAxis* axisCol = new QCategory3DAxis;
    axisCol->setTitle("column axis");
    axisCol->setTitleVisible(true);
    graph3D->setColumnAxis(axisCol);		//设置列坐标轴

    //创建序列
    series = new QBar3DSeries;
    series->setMesh(QAbstract3DSeries::MeshCylinder);       //棒柱形状
    series->setItemLabelFormat("(@rowLabel,@colLabel): %d");//项的标签显示格式
    graph3D->addSeries(series);

    //设置数据代理的数据
    QBarDataArray* dataArray = new QBarDataArray; //棒柱数据数组,typedef QList<QBarDataRow *> QBarDataArray;
    for (int i = 0; i <3; i++)   			  //行
    {
        QBarDataRow* dataRow = new QBarDataRow;   //棒柱数据行,typedef QList<QBarDataItem> QBarDataRow;
        for (int j = 1; j <= 5; j++)          //列
        {
            quint32 value = rand()%15+1;          //随机整数[1,15]
            QBarDataItem* dataItem = new QBarDataItem;//创建棒柱数据对象
            dataItem->setValue(value);            //设置棒柱的数据
            dataRow->append(*dataItem);           //添加到棒柱数据行
        }
        dataArray->append(dataRow);               //棒柱数据数组添加一个棒柱数据行
    }


    QStringList rowLabs;    //行坐标标签
    rowLabs << "Week1" << "Week2" << "Week3";
    series->dataProxy()->setRowLabels(rowLabs); //设置数据代理的行标签

    QStringList colLabs;    //列坐标标签
    colLabs << "Mon" << "Tue" << "Wed" << "Thur" << "Fri";
    series->dataProxy()->setColumnLabels(colLabs);//设置数据代理的列标签

    series->dataProxy()->resetArray(dataArray);   //重设数据代理的数据

    connect(series, &QBar3DSeries::selectedBarChanged,
             this, &mainwindow::do_barSelected);
}

2-1 设置项标签格式

如果没有为该系列显式设置数据代理,则该系列将创建默认代理。设置另一个代理将销毁现有代理以及添加到其中的所有数据。

标签格式 注释
@rowTitle 来自行轴的标题
@colTitle 列轴的标题
@valueTitle 来自值轴的标题
@rowIdx 可见行索引,使用图形区域设置进行了本地化
@colIdx 可见列索引,使用图形区域设置进行了本地化
@rowLabel 来自行轴的标签
@colLabel 来自列轴的标签
@valueLabel 使用附加到图形的值轴格式格式化的项值
@seriesName 系列的名称
%<format spec> 指定格式的项值。使用与QValue3DAxis::abelFormat相同的规则进行格式化

3 选中棒柱

cpp 复制代码
void mainwindow::do_barSelected(const QPoint& position)
{
    if (position.x() < 0 || position.y() < 0)  //必须加此判断
    {
        ui->actBar_ChangeValue->setEnabled(false);
        return;
    }

    ui->actBar_ChangeValue->setEnabled(true);
    const QBarDataItem* bar = series->dataProxy()->itemAt(position);
    QString info = QString::fromLocal8Bit("选中的棒柱,Row=%1, Column=%2, Value=%3")
        .arg(position.x()).arg(position.y()).arg(bar->value());
    ui->statusBar->showMessage(info);
}

(三) 3D部件创建及添加到窗口

1 序列颜色 - 设置序列基本颜色

cpp 复制代码
void mainwindow::on_actSeries_BaseColor_triggered()
{
    //设置序列基本颜色
    QColor  color = series->baseColor();
    color = QColorDialog::getColor(color);
    if (color.isValid())
    {
		series->setBaseColor(color);
	}        
}

2 重新生成 - 重新生成数据画图

cpp 复制代码
void mainwindow::on_actRedraw_triggered()
{
    QBarDataProxy* dataProxy = new QBarDataProxy;    //新建数据代理
    int rowCount = series->dataProxy()->rowCount();  //数据代理的行数
    for (int i = 0; i < rowCount; i++)  //行
    {
        QBarDataRow* dataRow = new QBarDataRow;       //棒柱数据行
        for (int j = 1; j <= 5; j++)     //列
        {
            quint32 value = rand() % (15 - 5 + 1) + 5;
            QBarDataItem* dataItem = new QBarDataItem;   //数据项
            dataItem->setValue(value);
            dataRow->append(*dataItem);
        }
        QString rowStr = QString::fromLocal8Bit("第%1周").arg(i + 1);
        dataProxy->addRow(dataRow, rowStr);     //添加行数据和标签
    }

    QStringList colLabs = series->dataProxy()->columnLabels();    //原来的列坐标轴标签
    dataProxy->setColumnLabels(colLabs);

    series->dataProxy()->resetArray();  //清除数据代理和坐标轴标签,必须清除,否则不能重新设置坐标轴标签
    series->setDataProxy(dataProxy);    //重新设置数据代理,会删除之前的数据代理
}

3 修改数值 - 修改选中棒柱的数值(F2)

cpp 复制代码
void mainwindow::on_actBar_ChangeValue_triggered()
{
    QPoint position = series->selectedBar();
    if (position.x() < 0 || position.y() < 0)   //必须加此判断
        return;

    QBarDataItem bar = *(series->dataProxy()->itemAt(position));
    qreal value = bar.value();    //原来的值

    bool ok;
    value = QInputDialog::getInt(this, QString::fromLocal8Bit("输入数值"),
                                       QString::fromLocal8Bit("更改棒柱数值"), value, 0, 50, 1, &ok);
    if (ok)
    {
        bar.setValue(value);
        series->dataProxy()->setItem(position, bar);
    }
}

4 添加行 - 添加一行

cpp 复制代码
void mainwindow::on_actData_Add_triggered()
{
    //添加行
     const QString rowLabel = QInputDialog::getText(this,
                                 QString::fromLocal8Bit("输入字符串"),
                                 QString::fromLocal8Bit("请输入行标签"));

    if (rowLabel.isEmpty())
        return;

    QBarDataRow* dataRow = new QBarDataRow;       //棒柱数据行
    for (int j = 1; j <= 5; j++)     //固定5列
    {
        quint32 value = rand()%(25 - 15 + 1) + 15;
        QBarDataItem* dataItem = new QBarDataItem;
        dataItem->setValue(value);
        dataRow->append(*dataItem);
    }
    series->dataProxy()->addRow(dataRow, rowLabel);     //添加棒柱数据行和标签

  
}

5 插入行 - 插入一行

cpp 复制代码
void mainwindow::on_actData_Insert_triggered()
{
    //插入行
    QString rowLabel = QInputDialog::getText(this, QString::fromLocal8Bit("输入字符串"), 
                                                   QString::fromLocal8Bit("请输入行标签"));
    if (rowLabel.isEmpty())
        return;
  

    QPoint position = series->selectedBar();
    int index = position.x(); //当前行号
    if (index < 0)
        index = 0;

    QBarDataRow* dataRow = new QBarDataRow;       //棒柱数据行
    for (int j = 1; j <= 5; j++)     //固定5列
    {
        quint32 value = rand() % (30 - 20) + 20; 
        QBarDataItem* dataItem = new QBarDataItem;
        dataItem->setValue(value);
        dataRow->append(*dataItem);
    }
    series->dataProxy()->insertRow(index, dataRow);    //插入棒柱数据行
    
}

6 删除行 - 删除当前行

cpp 复制代码
void mainwindow::on_actData_Delete_triggered()
{

    QPoint position = series->selectedBar();
    if (position.x() < 0 || position.y() < 0)
        return;

    int rowIndex = position.x();  //当前行号
    int removeCount = 1;          //删除的行数
    int removeLabels = true;      //是否删除行标签
    series->dataProxy()->removeRows(rowIndex, removeCount, removeLabels);
}

7 退出 - 退出本程序

cpp 复制代码
void mainwindow::on_actQiut_triggered()
{
    QApplication::quit();
}

(四) "旋转和平移"分组框功能

1 预设视角

cpp 复制代码
void mainwindow::on_comboCamera_currentIndexChanged(int index)
{
    Q3DCamera::CameraPreset  cameraPos =  Q3DCamera::CameraPreset(index);
    graph3D->scene()->activeCamera()->setCameraPreset(cameraPos);
}

预设视角类型参考 enum Q3DCamera::CameraPreset

2 水平旋转

cpp 复制代码
void mainwindow::on_sliderH_valueChanged(int value)
{
    graph3D->scene()->activeCamera()->setXRotation(value);
}

3 垂直旋转

cpp 复制代码
void mainwindow::on_sliderV_valueChanged(int value)
{
    graph3D->scene()->activeCamera()->setYRotation(value);
}

4 缩放

cpp 复制代码
void mainwindow::on_sliderZoom_valueChanged(int value)
{
    graph3D->scene()->activeCamera()->setZoomLevel(value);
}

5 下移

cpp 复制代码
void mainwindow::on_btnMoveDown_clicked()
{
    QVector3D target3D = graph3D->scene()->activeCamera()->target();
    qreal z = target3D.z();
    target3D.setZ(z + 0.1);
    graph3D->scene()->activeCamera()->setTarget(target3D);
}

6 上移

cpp 复制代码
void mainwindow::on_btnMoveUp_clicked()
{
    QVector3D target3D = graph3D->scene()->activeCamera()->target();
    qreal z = target3D.z();
    target3D.setZ(z - 0.1);
    graph3D->scene()->activeCamera()->setTarget(target3D);
}

7 左移

cpp 复制代码
void mainwindow::on_btnMoveLeft_clicked()
{
    QVector3D target3D = graph3D->scene()->activeCamera()->target();
    qreal x = target3D.x();
    target3D.setX(x + 0.1);
    graph3D->scene()->activeCamera()->setTarget(target3D);
}

8 右移

cpp 复制代码
void mainwindow::on_btnMoveRight_clicked()
{
    QVector3D target3D = graph3D->scene()->activeCamera()->target();
    qreal x = target3D.x();
    target3D.setX(x - 0.1);
    graph3D->scene()->activeCamera()->setTarget(target3D);
}

9 复位(到 FrontHigh 视角)

cpp 复制代码
void mainwindow::on_btnResetCamera_clicked()
{
    graph3D->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFrontHigh);

(五) "图形总体"分组框功能

1 显示选中棒柱的标签 CheckBox

cpp 复制代码
void mainwindow::on_cBoxTheme_currentIndexChanged(int index)
{
    Q3DTheme* currentTheme = graph3D->activeTheme();
    currentTheme->setType(Q3DTheme::Theme(index));
}

2 轴标签字体大小

cpp 复制代码
void mainwindow::on_spinFontSize_valueChanged(int arg1)
{
    QFont font = graph3D->activeTheme()->font();
    font.setPointSize(arg1);
    graph3D->activeTheme()->setFont(font);   
}

3 选择模式

cpp 复制代码
void mainwindow::on_cBoxSelectionMode_currentIndexChanged(int index)
{
    graph3D->setSelectionMode(QAbstract3DGraph::SelectionFlags(index));
}

4 显示背景 CheckBox

cpp 复制代码
void mainwindow::on_chkBoxBackground_clicked(bool checked)
{
    graph3D->activeTheme()->setBackgroundEnabled(checked);
}

4-1 选择模式

enum QAbstract3DGraph::SelectionFlag

枚举值 含义
QAbstract3DGraph::SelectionNone 不允许选择
QAbstract3DGraph::SelectionItem 选择并且高亮显示一个项
QAbstract3DGraph::SelectionRow 选择并且高亮显示一行
QAbstract3DGraph::SelectionItemAndRow 选择一个项和一行,用不同颜色高亮显示
QAbstract3DGraph::SelectionColumn 选择并且高亮显示一列
QAbstract3DGraph::SelectionItemAndColumn 选择一个项和一列,用不同颜色高亮显示
QAbstract3DGraph::SelectionRowAndColumn 选择交叉的一行和一列
QAbstract3DGraph::SelectionItemRowAndColumn 选择交叉的一行和一列,用不同颜色高亮显示
QAbstract3DGraph::SelectionSlice 切片选择,需要与 SelectionRow 或 SelectionColumn 结合使用
QAbstract3DGraph::SelectionMultiSeries 选中同一个位置处的多个序列的项

5 显示背景网格 CheckBox

cpp 复制代码
void mainwindow::on_chkBoxGrid_clicked(bool checked)
{
    graph3D->activeTheme()->setGridEnabled(checked);
}

6 显示倒影 CheckBox

cpp 复制代码
void mainwindow::on_chkBoxReflection_clicked(bool checked)
{
    graph3D->setReflection(checked);
}

7 数值坐标轴反向 CheckBox

cpp 复制代码
void mainwindow::on_chkBoxReverse_clicked(bool checked)
{
    graph3D->valueAxis()->setReversed(checked);
}

8 显示轴标题 CheckBox

cpp 复制代码
void mainwindow::on_chkBoxAxisTitle_clicked(bool checked)
{
    graph3D->valueAxis()->setTitleVisible(checked);
    graph3D->rowAxis()->setTitleVisible(checked);
    graph3D->columnAxis()->setTitleVisible(checked);
}

9 显示轴标签背景 CheckBox

cpp 复制代码
void mainwindow::on_chkBoxAxisBackground_clicked(bool checked)
{
    graph3D->activeTheme()->setLabelBackgroundEnabled(checked);
}

(六) "序列设置"分组框功能

1 棒柱样式 ComboBox

cpp 复制代码
void mainwindow::on_cBoxBarStyle_currentIndexChanged(int index)
{
    QAbstract3DSeries::Mesh aMesh;
    aMesh = QAbstract3DSeries::Mesh(index + 1);  //0=MeshUserDefined
    series->setMesh(aMesh);
}

1-1 棒柱形状

enum QAbstract3DSeries::Mesh
并非所有样式都可用于所有可视化类型。

常量 注释
QAbstract3DSeries::MeshUserDefined 0 用户定义网格,通过QAbstract3DSeries::userDefinedMesh属性设置
QAbstract3DSeries::MeshBar 1 基本矩形条
QAbstract3DSeries::MeshCube 2 基本多维数据集
QAbstract3DSeries::MeshPyramid 3 四边形金字塔
QAbstract3DSeries::MeshCone 4 基本圆锥体
QAbstract3DSeries::MeshCylinder 5 基本气缸
QAbstract3DSeries::MeshBevelBar 6 略微倾斜(圆形)的矩形钢筋
QAbstract3DSeries::MeshBevelCube 7 略微倾斜(圆形)的立方体
QAbstract3DSeries::MeshSphere 8 球体
QAbstract3DSeries::MeshMinimal 9 最小的三维网格:一个三角锥
QAbstract3DSeries::MeshArrow 10 向上的箭头
QAbstract3DSeries::MeshPoint 11 2D点

2 光滑效果 CheckBox

cpp 复制代码
void mainwindow::on_chkBoxSmooth_clicked(bool checked)
{
    series->setMeshSmooth(checked);
}

3 显示选中棒柱的标签 CheckBox

cpp 复制代码
void mainwindow::on_chkBoxItemLabel_clicked(bool checked)
{
        series->setItemLabelFormat("value at (@rowLabel,@colLabel): %.1f");
        series->setItemLabelVisible(checked);
}

(七) 有关QBarDataProxy数据管理接口

函数 功能
int addRow() 添加一行数据,一行数据是 QBarDataRow 类型对象
void insertRow() 在某行之前插入一行数据
void removeRows() 从某行开始,移除指定行数的数据
void setRow () 为某一行重新设置一行数据
QBarDataRow *rowAt() 返回某一行的数据
void setItem() 根据行号和列号,设置某个棒柱数据项
QBarDataltem *itemAt() 根据行号和列号,返回单个棒柱数据项
void resetArray() 若不带任何参数,就清除数据代理所有的数据和标签;若使用一个 QBarDataArray类型的对象作为输入参数,就重新设置棒柱数据数组
int rowCount() 返回数据代理的行数
void setRowLabels() 用一个字符串列表设置行坐标轴的标签
StringList rowLabels() 返回行坐标轴的所有标签
void setColumnLabels() 用一个字符串列表设置列坐标轴的标签
QStringList columnLabels() 返回列坐标轴的所有标签
相关推荐
云空8 分钟前
《解锁 Python 数据挖掘的奥秘》
开发语言·python·数据挖掘
青莳吖18 分钟前
Java通过Map实现与SQL中的group by相同的逻辑
java·开发语言·sql
逆旅行天涯23 分钟前
【Threejs】从零开始(六)--GUI调试开发3D效果
前端·javascript·3d
Buleall25 分钟前
期末考学C
java·开发语言
重生之绝世牛码27 分钟前
Java设计模式 —— 【结构型模式】外观模式详解
java·大数据·开发语言·设计模式·设计原则·外观模式
小蜗牛慢慢爬行33 分钟前
有关异步场景的 10 大 Spring Boot 面试问题
java·开发语言·网络·spring boot·后端·spring·面试
Algorithm157643 分钟前
云原生相关的 Go 语言工程师技术路线(含博客网址导航)
开发语言·云原生·golang
shinelord明1 小时前
【再谈设计模式】享元模式~对象共享的优化妙手
开发语言·数据结构·算法·设计模式·软件工程
Monly211 小时前
Java(若依):修改Tomcat的版本
java·开发语言·tomcat
boligongzhu1 小时前
DALSA工业相机SDK二次开发(图像采集及保存)C#版
开发语言·c#·dalsa