从零开始学Qt(98):三维柱状图绘制实例

从零开始学Qt(98):三维柱状图绘制实例

首页休闲益智形状滚轮更新时间:2024-07-29

本文通过一个三维柱状图的实例来说明使用Data Visualization的类绘制三维图形的基本原理。实例使用Q3DBars绘制一个三维柱状图,程序运行效果如图所示。

无需额外编程或设置,程序运行时在图表单击左键可以选择图表中的某个项、某个列或行(与选择方式的设置有关),按住鼠标右键时上下、左右移动可以进行水平和垂直方向的旋转,鼠标滚轮可以进行缩放。

主窗口设计

实例主窗口继承自QWidget的应用程序,可视化创建主窗体。

由于三维图形类Q3DBars、Q3DScatter和Q3DSurface都是从QWindow继承而来的,不能简单使用QWidget组件作为Q3DBars组件的容器,也就是不能在主窗口上放置一个QWidget组件,然后作为Q3DBars组件的容器,而是需要使用QWidget::createWindowContainer()动态创建QWidget作为Q3DBars的容器。

主窗口类的头文件widget.h中的定义如下:

class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: Ui::Widget *ui; QWidget *graphContainer; //图表的容器 Q3DBars *graph3D; //图表 QBar3DSeries *series; //图表的序列 void iniGraph3D(); //创建图表 };

在Widget类中,定义了私有变量graphContainer作为三维图表的容器,它在的构造函数中创建。还定义三维图表和序列的私有变量graph3D和series,是为了在程序里便于直接引用。iniGraph3D()函数用于初始化创建图表,在构造函数里调用。

三维柱状图的创建

在主窗口的构造函数里创建界面和三维图表,构造函数代码如下:

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); //创建图表 graph3D = new Q3DBars(); graphContainer = QWidget::createWindowContainer(graph3D); QLayout *layout=new QVBoxLayout(this); layout->addWidget(graphContainer); this->setLayout(layout); //创建坐标轴 QStringList rowLabs; QStringList colLabs; rowLabs<<"row1"<<"row2"<<"row3"; colLabs<<"col1"<<"col2"<<"col3"<<"col4"<<"col5"; QValue3DAxis *axisV=new QValue3DAxis; //数值坐标轴 axisV->setTitle("value"); axisV->setTitleVisible(true); QCategory3DAxis *axisRow=new QCategory3DAxis; //行坐标轴 axisRow->setTitle("row axis"); axisRow->setLabels(rowLabs); axisRow->setTitleVisible(true); QCategory3DAxis *axisCol=new QCategory3DAxis; //列坐标轴 axisCol->setTitle ("column axis"); axisCol->setLabels(colLabs); axisCol->setTitleVisible(true); graph3D->setValueAxis(axisV); graph3D->setRowAxis(axisRow); graph3D->setColumnAxis(axisCol); //创建序列 series = new QBar3DSeries; series->setMesh(QAbstract3DSeries::MeshCylinder); //棒图形状 series->setItemLabelFormat("(@rowLabel,@colLabel) : %.1f");//标签格式 graph3D->addSeries(series); //添加数据 QBarDataArray *dataSet = new QBarDataArray; //数据数组 dataSet->reserve(rowLabs.count()); QBarDataRow *dataRow = new QBarDataRow; *dataRow << 1 << 2<< 3<< 4<<5; //第 1 行数据,有 5 列 dataSet->append(dataRow); QBarDataRow *dataRow2 = new QBarDataRow; *dataRow2 << 5<< 5<< 5<< 5<<5; //第 2 行数据,有 5 列 dataSet->append(dataRow2); QBarDataRow *dataRow3 = new QBarDataRow; *dataRow3 << 1<< 5<< 9<< 5<<1; //第 3 行数据,有 5 列 dataSet->append(dataRow3); series->dataProxy()->resetArray(dataSet); }

程序首先创建Q3DBars类的实例graph3D,然后创建一个QWidget实例graphContainer作为其容器。创建graphContainer时使用了QWidget的静态函数createWindowContainer(),这样创建的QWidget实例才可以作为QWindow及其子类组件的容器。

三维柱状图的水平面的两个轴采用QCategory3DAxis类型的坐标轴,是文字型标签坐标轴,分别为其设置轴标题和轴标签。垂直方向表示项的数值大小,所以使用QValue3DAxis类型的坐标轴。创建坐标轴后,分别设置为柱状图行坐标轴、列坐标轴和数值坐标轴:

graph3D->setValueAxis(axisV); graph3D->setRowAxis(axisRow); graph3D->setColumnAxis(axisCol);

与Q3DBars对应使用的序列是QBar3DSeries类,创建序列实例对象series,设置棒图性质和标签格式后添加到图表。

然后创建QBarDataArray数组dataSet,其元素个数等于三维柱状图的行数,也就是dataSet的每个元素是一个行的数据。

一个行的数据是QBarDataRow类型,例如,创建第1行的数据并添加到柱状图的数据数组里的代码如下:

QBarDataRow *dataRow = new QBarDataRow; *dataRow << 1 << 2<< 3<< 4<<5; //第 1 行数据,有 5 列 dataSet->append(dataRow);

实际上,QBarDataRow和QBarDataArray都不是类,而是类型定义,在Qt的源代码中,它们的定义如下:

typedef QVector<QBarDataItem> QBarDataRow; typedef QList<QBarDataRow *> QBarDataArray;

所以,QBarDataRow是QBarDataItem的向量,QBarDataArray是QBarDataRow的列表。数据的基本元素是QBarDataItem,也就是柱状图中的一个项,QBarDataItem只有value和rotation两个属性,用于存储项的数值和旋转角度。

在图中,柱状图的数据有3行5列,添加数据时,每次添加一行的数据,但是属于一个序列。

设置完数据后,为序列的数据代理设置数据,语句如下:

series->dataProxy()->resetArray(dataSet);

程序里没有为序列先创建QBarDataProxy类型的数据代理,然后再添加到序列里。调用series->dataProxy()使用内部缺省的数据代理,resetArray(dataSet)将清除数据代理原有的数据,并使用dataSet作为数据源。

————————————————

觉得有用的话请关注点赞,谢谢您的支持!

对于本系列文章相关示例完整代码有需要的朋友,可关注并在评论区留言!

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved