Qt開發(fā)技術(shù):Q3D圖表開發(fā)筆記(二):Q3DBar三維柱狀圖介紹、Demo以及代碼詳解
前言
??qt提供了q3d進(jìn)行三維開發(fā),雖然這個(gè)框架沒(méi)有得到大量運(yùn)用也不是那么成功,性能上也有很大的欠缺,但是普通的點(diǎn)到為止的應(yīng)用展示還是可以的。
??其中就包括華麗絢爛的三維圖表,數(shù)據(jù)量不大的時(shí)候是可以使用的。
??上一篇介紹了基礎(chǔ)的q3d散點(diǎn)圖,本篇介紹基礎(chǔ)的柱狀圖。
Demo:Q3DScatter散點(diǎn)圖演示效果
??

??

??

Q3D提供的三維圖表
??依賴QtDataVisualization。在安裝qt的時(shí)候要選擇安裝QtDataVisualization模塊。
Q3DScatter散點(diǎn)圖
??Q3D的散點(diǎn)圖,性能大約支撐1000個(gè)點(diǎn)可以不卡頓,具體依賴pc,1000個(gè)點(diǎn)是什么 概念,可以理解為:10x10x10的區(qū)域,每個(gè)區(qū)域一個(gè)數(shù)據(jù)點(diǎn)。
??

Q3DBars柱狀圖
??Q3D的柱狀圖,性能跟散點(diǎn)圖類似。
???

Q3DSurface平面凹凸圖,平面紋理圖
??Q3D的柱狀圖,性能跟散點(diǎn)圖類似。
??

# Q3DBar柱狀圖 ## 簡(jiǎn)介 ??Q3DBars類提供了用于渲染三維條形圖的方法。 ??該類使開發(fā)人員能夠以3D方式渲染條形圖,并通過(guò)自由旋轉(zhuǎn)場(chǎng)景來(lái)查看它們。
旋轉(zhuǎn):通過(guò)按住鼠標(biāo)右鍵并移動(dòng)鼠標(biāo)來(lái)完成的。
縮放:通過(guò)鼠標(biāo)滾輪完成的。
選擇:如果啟用了選擇,則通過(guò)鼠標(biāo)左鍵進(jìn)行選擇。
重置視角:通過(guò)單擊鼠標(biāo)滾輪,可以將場(chǎng)景重置為默認(rèn)的攝影機(jī)視圖。
??在觸摸設(shè)備中,旋轉(zhuǎn)通過(guò)點(diǎn)擊和移動(dòng)來(lái)完成,選擇通過(guò)點(diǎn)擊和按住來(lái)完成,縮放通過(guò)捏來(lái)完成。
??如果沒(méi)有將任何軸明確設(shè)置為Q3DBar,則會(huì)創(chuàng)建不帶標(biāo)簽的臨時(shí)默認(rèn)軸。這些默認(rèn)軸可以通過(guò)軸訪問(wèn)器進(jìn)行修改,但只要明確設(shè)置了方向的任何軸,該方向的默認(rèn)軸就會(huì)被破壞。
Q3DBars支持同時(shí)顯示多個(gè)系列。并非所有系列都必須具有相同數(shù)量的行和列。行和列標(biāo)簽取自第一個(gè)添加的系列,除非明確定義為行和列軸。
構(gòu)造最小Q3D柱狀圖
??首先,構(gòu)造一個(gè)Q3DBars實(shí)例。由于在本例中,我們將圖形作為頂級(jí)窗口運(yùn)行,因此需要清除Qt::FramelessWindowHint標(biāo)志,該標(biāo)志在默認(rèn)情況下設(shè)置:
Q3DBars bars;bars.setFlags(bars.flags() ^ Qt::FramelessWindowHint);
??構(gòu)造Q3DBar后,可以通過(guò)更改行和列軸上的范圍來(lái)設(shè)置數(shù)據(jù)窗口。這不是強(qiáng)制性的,因?yàn)閿?shù)據(jù)窗口將默認(rèn)顯示系列中的所有數(shù)據(jù)。如果數(shù)據(jù)量很大,通常最好只顯示其中的一部分。例如,讓我們將數(shù)據(jù)窗口設(shè)置為顯示前五行和前五列:
bars.rowAxis()->setRange(0, 4);bars.columnAxis()->setRange(0, 4);
??現(xiàn)在Q3DBars已經(jīng)準(zhǔn)備好接收要渲染的數(shù)據(jù)了。創(chuàng)建一個(gè)包含一行5個(gè)值的序列:
QBar3DSeries *series = new QBar3DSeries;QBarDataRow *data = new QBarDataRow;*data << 1.0f << 3.0f << 7.5f << 5.0f << 2.2f;series->dataProxy()->addRow(data);bars.addSeries(series);
??注意:數(shù)據(jù)窗口設(shè)置為5 x 5,但只添加了一行數(shù)據(jù)。沒(méi)添加的其余的行將是空白的。
??最后,設(shè)置為可見:
bars.show();
??創(chuàng)建和顯示此圖所需的完整代碼為:
#include <QtDataVisualization>using namespace QtDataVisualization;int main(int argc, char **argv){
? ?QGuiApplication app(argc, argv);
? ?Q3DBars bars;
? ?bars.setFlags(bars.flags() ^ Qt::FramelessWindowHint);
? ?bars.rowAxis()->setRange(0, 4);
? ?bars.columnAxis()->setRange(0, 4);
? ?QBar3DSeries *series = new QBar3DSeries;
? ?QBarDataRow *data = new QBarDataRow;
? ?*data << 1.0f << 3.0f << 7.5f << 5.0f << 2.2f;
? ?series->dataProxy()->addRow(data);
? ?bars.addSeries(series);
? ?bars.show();
? ?return app.exec();}
??運(yùn)行效果:
??

??場(chǎng)景可以被旋轉(zhuǎn)、放大,并且可以選擇一個(gè)項(xiàng)目來(lái)查看其位置,但在這個(gè)最小的代碼示例中不包括其他交互。
Q3Ddemo構(gòu)建流程解析
步驟一:確認(rèn)安裝QtDataVisualization模塊
??如何確認(rèn),則是在幫助文件中查看是否有Q3dscatter類。一般是安裝了模塊才會(huì)有對(duì)應(yīng)的幫助文件。沒(méi)有則重新安裝qt或者單獨(dú)安裝該模塊。
???

步驟二:工程配置文件中加入模塊
??Q3d是在數(shù)據(jù)可視化模塊中,需要在pro或者pri配置文件中添加。
QT += datavisualization
??

步驟三:添加使用到的頭文件
使用到Q3DBar相關(guān)類中添加頭文件,主要使用到Q3DBar、QBar3DSeries、QBarDataRow等等。
#include <Q3DBars>#include <Q3DTheme>#include <QBar3DSeries>#include <QVector3D>
??

步驟四:添加命名空間
??這時(shí)候還是無(wú)法使用對(duì)應(yīng)的類,需要添加命名空間才行:
using namespace QtDataVisualization;
??

步驟五:Q3D的圖標(biāo)基礎(chǔ)構(gòu)建框架
??下面是包含注釋的Q3DBar基礎(chǔ)構(gòu)建流程,其與散點(diǎn)圖在軸(軸名稱和軸使用等)和數(shù)據(jù)(添加數(shù)據(jù)方式為每一個(gè)占位基本都需要,除非你能直接闊過(guò)去,從頭開始添加的中間有0則不好處理,需要添加0來(lái)占位,QBarDataRow自動(dòng)依次排序的)
_pQ3DBars = new Q3DBars();_pContainer = QWidget::createWindowContainer(_pQ3DBars, this);// 設(shè)置軸文本{
? ?QStringList strList;
? ?_pQ3DBars->rowAxis()->setTitle("年");
? ?_pQ3DBars->rowAxis()->setTitleVisible(true);
? ?strList.clear();
? ?strList << "2010" << "2011" << "2012" << "2013" << "2014"
? ? ? ? ? ? ? << "2015" << "2016" << "2017" << "2018" << "2019"
? ? ? ? ? ? ? << "2020" << "2021" << "2022" << "2023" ;
? ?_pQ3DBars->rowAxis()->setLabels(strList);
? ?_pQ3DBars->columnAxis()->setTitle("月");
? ?strList.clear();
? ?strList << "1" << "2" << "3" << "4" << "5"
? ? ? ? ? ? ? ?<< "6" << "7" << "8" << "9" << "10"
? ? ? ? ? ? ? ?<< "11" << "12";
? ?_pQ3DBars->columnAxis()->setLabels(strList);
? ?_pQ3DBars->columnAxis()->setTitleVisible(true);
? ?_pQ3DBars->valueAxis()->setTitle("銷售額(萬(wàn)元)");
? ?_pQ3DBars->valueAxis()->setTitleVisible(true);}// 設(shè)置軸范圍{
? ?_pQ3DBars->rowAxis()->setRange(2010 - 2010, 2023 - 2010); ? // 從0開始
? ?_pQ3DBars->columnAxis()->setRange(1 - 1, 12 - 1); ? ? ? ? ? // 從0開始
? ?_pQ3DBars->valueAxis()->setRange(0, 40);}// 生成一個(gè)曲線_pBar3DSeries = new QBar3DSeries(_pQ3DBars);// 設(shè)置渲染平滑_pBar3DSeries->setMeshSmooth(true);// 視圖添加該曲線_pQ3DBars->addSeries(_pBar3DSeries);// 設(shè)置陰影質(zhì)量_pQ3DBars->setShadowQuality(QAbstract3DGraph::ShadowQualitySoftLow);// 設(shè)置視角_pQ3DBars->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetIsometricLeft);// 設(shè)置子網(wǎng)格_pQ3DBars->activeTheme()->setGridEnabled(true);#if 1// 添加模擬數(shù)據(jù)QBarDataArray data;for(int year = 2010; year <= 2023; year++){
? ?QBarDataRow *pBarDataRow = new QBarDataRow;
? ?for(int month = 1; month <= 12; month++)
? ?{
? ? ? ?if(year == 2023 && month >= 4)
? ? ? ?{
? ? ? ? ? ?LOG << year << month;
? ? ? ? ? ?// 當(dāng)前2023年4月,無(wú)數(shù)據(jù)
? ? ? ? ? ?*pBarDataRow << 0;
? ? ? ?}else{
? ? ? ? ? ?*pBarDataRow << ((year - 2010) + month);
? ? ? ?}
? ?}
? ?data << pBarDataRow;}// 添加數(shù)據(jù)(自動(dòng)沖掉之前的數(shù)據(jù))_pBar3DSeries->dataProxy()->addRows(data);#endif
Demo源碼
Q3dBarWidget.h#ifndef Q3DBARWIDGET_H#define Q3DBARWIDGET_H#include <QWidget>#include <Q3DBars>#include <Q3DTheme>#include <QBar3DSeries>#include <QVector3D>using namespace QtDataVisualization;namespace Ui {class Q3dBarWidget;}class Q3dBarWidget : public QWidget{
? ?Q_OBJECTpublic:
? ?explicit Q3dBarWidget(QWidget *parent = 0);
? ?~Q3dBarWidget();protected:
? ?void initControl();protected:
? ?void resizeEvent(QResizeEvent *event);private:
? ?Ui::Q3dBarWidget *ui;private:
? ?Q3DBars *_pQ3DBars; ? ? ? ? ? ? // q3d柱狀視圖
? ?QWidget *_pContainer; ? ? ? ? ? // q3d窗口容器
? ?QBar3DSeries *_pBar3DSeries; ? ?// q3d柱狀圖數(shù)據(jù)};#endif // Q3DBARWIDGET_H
Q3dBarWidget.cpp
#include "Q3dBarWidget.h"#include "ui_Q3dBarWidget.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")Q3dBarWidget::Q3dBarWidget(QWidget *parent) :
? ?QWidget(parent),
? ?ui(new Ui::Q3dBarWidget),
? ?_pQ3DBars(0),
? ?_pContainer(0),
? ?_pBar3DSeries(0){
? ?ui->setupUi(this);
? ?QString version = "v1.0.0";
? ?setWindowTitle(QString("q3d柱狀圖示例 %1(作者:長(zhǎng)沙紅胖子 QQ:21497936 WX:15173255813 www.hpzwl.com").arg(version));
? ?initControl();}Q3dBarWidget::~Q3dBarWidget(){
? ?delete ui;}void Q3dBarWidget::initControl(){
? ?_pQ3DBars = new Q3DBars();
? ?_pContainer = QWidget::createWindowContainer(_pQ3DBars, this);
? ?// 設(shè)置軸文本
? ?{
? ? ? ?QStringList strList;
? ? ? ?_pQ3DBars->rowAxis()->setTitle("年");
? ? ? ?_pQ3DBars->rowAxis()->setTitleVisible(true);
? ? ? ?strList.clear();
? ? ? ?strList << "2010" << "2011" << "2012" << "2013" << "2014"
? ? ? ? ? ? ? ?<< "2015" << "2016" << "2017" << "2018" << "2019"
? ? ? ? ? ? ? ?<< "2020" << "2021" << "2022" << "2023" ;
? ? ? ?_pQ3DBars->rowAxis()->setLabels(strList);
? ? ? ?_pQ3DBars->columnAxis()->setTitle("月");
? ? ? ?strList.clear();
? ? ? ?strList << "1" << "2" << "3" << "4" << "5"
? ? ? ? ? ? ? ?<< "6" << "7" << "8" << "9" << "10"
? ? ? ? ? ? ? ?<< "11" << "12";
? ? ? ?_pQ3DBars->columnAxis()->setLabels(strList);
? ? ? ?_pQ3DBars->columnAxis()->setTitleVisible(true);
? ? ? ?_pQ3DBars->valueAxis()->setTitle("銷售額(萬(wàn)元)");
? ? ? ?_pQ3DBars->valueAxis()->setTitleVisible(true);
? ?}
? ?// 設(shè)置軸范圍
? ?{
? ? ? ?_pQ3DBars->rowAxis()->setRange(2010 - 2010, 2023 - 2010); ? // 從0開始
? ? ? ?_pQ3DBars->columnAxis()->setRange(1 - 1, 12 - 1); ? ? ? ? ? // 從0開始
? ? ? ?_pQ3DBars->valueAxis()->setRange(0, 40);
? ?}
? ?// 生成一個(gè)曲線
? ?_pBar3DSeries = new QBar3DSeries(_pQ3DBars);
? ?// 設(shè)置渲染平滑
? ?_pBar3DSeries->setMeshSmooth(true);
? ?// 視圖添加該曲線
? ?_pQ3DBars->addSeries(_pBar3DSeries);
? ?// 設(shè)置陰影質(zhì)量
? ?_pQ3DBars->setShadowQuality(QAbstract3DGraph::ShadowQualitySoftLow);
? ?// 設(shè)置視角
? ?_pQ3DBars->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetIsometricLeft);
? ?// 設(shè)置子網(wǎng)格
? ?_pQ3DBars->activeTheme()->setGridEnabled(true);#if 1
? ?// 添加模擬數(shù)據(jù)
? ?QBarDataArray data;
? ?for(int year = 2010; year <= 2023; year++)
? ?{
? ? ? ?QBarDataRow *pBarDataRow = new QBarDataRow;
? ? ? ?for(int month = 1; month <= 12; month++)
? ? ? ?{
? ? ? ? ? ?if(year == 2023 && month >= 4)
? ? ? ? ? ?{
? ? ? ? ? ? ? ?LOG << year << month;
? ? ? ? ? ? ? ?// 當(dāng)前2023年4月,無(wú)數(shù)據(jù)
? ? ? ? ? ? ? ?*pBarDataRow << 0;
? ? ? ? ? ?}else{
? ? ? ? ? ? ? ?*pBarDataRow << ((year - 2010) + month);
? ? ? ? ? ?}
? ? ? ?}
? ? ? ?data << pBarDataRow;
? ?}
? ?// 添加數(shù)據(jù)(自動(dòng)沖掉之前的數(shù)據(jù))
? ?_pBar3DSeries->dataProxy()->addRows(data);#endif}void Q3dBarWidget::resizeEvent(QResizeEvent *event){
? ?if(_pContainer)
? ?{
? ? ? ?_pContainer->setGeometry(rect());
? ?}}
工程模板v1.1.0
??
