QT5.14.2自带Examples:Bars

概述

本示在Widget应用程序中使用Q3DBars绘制3D柱状图,显示芬兰奥卢和赫尔辛基的平均气温(2006-2013),并通过UI操作,对显示效果进行调整。展示了以下内容:

  • 使用Q3DBars和一些widget创建应用程序
  • 使用QBar3DSeries和QBarDataProxy将数据设置到图形
  • 使用widget控件调整一些图形和序列属性
  • 通过单击轴标签选择行或列

QT5.14.2自带Examples:Bars_第1张图片

实现步骤

生成工程

新建一个空的Qt Application Widget工程。
右击文件名,选择Remove,删除mainwindow.h和mainwindow.cpp文件。这里我们不需要主窗口。我们将在main函数中创建一个QWidget对象作为显示窗口。
QT5.14.2自带Examples:Bars_第2张图片
在pro工程文件中,加入对Q3Dbars的支持:QT += datavisualization

main函数1(Q3Dbars对象与布局)

#include 
#include 

//Q3DBars的支持
#include 
#include 
#include 
using namespace QtDataVisualization;

int main(int argc, char *argv[])
{
     
    QApplication a(argc, argv);

    Q3DBars *widgetgraph = new Q3DBars();
    //所有的数据展示图表类对象,都必须装到容器使用。
    QWidget *container = QWidget::createWindowContainer(widgetgraph);

    if (!widgetgraph->hasContext()) {
     
        QMessageBox msgBox;
        msgBox.setText("Couldn't initialize the OpenGL context.");
        msgBox.exec();
        return -1;
    }
    //设置图形的大小规则
    QSize screenSize = widgetgraph->screen()->size();
    container->setMinimumSize(QSize(screenSize.width() / 2, screenSize.height() / 1.5));
    container->setMaximumSize(screenSize);
    container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    //widget通过选项卡和单击接受焦点
    container->setFocusPolicy(Qt::StrongFocus);

    QWidget *widget=new QWidget;
    widget->setWindowTitle(QStringLiteral("芬兰奥卢和赫尔辛基的平均气温(2006-2013)"));
    QHBoxLayout *hLayout = new QHBoxLayout(widget);
    QVBoxLayout *vLayout = new QVBoxLayout();
    hLayout->addWidget(container, 1);
    hLayout->addLayout(vLayout);

    widget->show();
    return a.exec();
}

运行效果如下,可以看到一个没有数据的三维坐标,可以通过鼠标控制显示角度:
QT5.14.2自带Examples:Bars_第3张图片

main函数2(vLayout布局)

右边部分是一个vLayout布局,用于控制左边的显示效果。我们先将控件准备好。

     //! [旋转控制Slider]
    QSlider *rotationSliderX = new QSlider(Qt::Horizontal, widget);
    rotationSliderX->setTickInterval(30);
    rotationSliderX->setTickPosition(QSlider::TicksBelow);
    rotationSliderX->setMinimum(-180);
    rotationSliderX->setValue(0);
    rotationSliderX->setMaximum(180);
    QSlider *rotationSliderY = new QSlider(Qt::Horizontal, widget);
    rotationSliderY->setTickInterval(15);
    rotationSliderY->setTickPosition(QSlider::TicksAbove);
    rotationSliderY->setMinimum(-90);
    rotationSliderY->setValue(0);
    rotationSliderY->setMaximum(90);
    vLayout->addWidget(new QLabel(QStringLiteral("Rotate horizontally")));
    vLayout->addWidget(rotationSliderX, 0, Qt::AlignTop);
    vLayout->addWidget(new QLabel(QStringLiteral("Rotate vertically")));
    vLayout->addWidget(rotationSliderY, 0, Qt::AlignTop);
     //! [旋转控制Slider]
     //! [效果切换按钮]
    QPushButton *labelButton = new QPushButton(widget);
    labelButton->setText(QStringLiteral("Change label style"));
    QPushButton *cameraButton = new QPushButton(widget);
    cameraButton->setText(QStringLiteral("Change camera preset"));
    QPushButton *zoomToSelectedButton = new QPushButton(widget);
    zoomToSelectedButton->setText(QStringLiteral("Zoom to selected bar"));
    vLayout->addWidget(labelButton, 0, Qt::AlignTop);
    vLayout->addWidget(cameraButton, 0, Qt::AlignTop);
    vLayout->addWidget(zoomToSelectedButton, 0, Qt::AlignTop);
    //! [效果切换按钮]
    //! [显示效果开关复选框]
    QCheckBox *backgroundCheckBox = new QCheckBox(widget);
    backgroundCheckBox->setText(QStringLiteral("Show background"));
    backgroundCheckBox->setChecked(false);

    QCheckBox *gridCheckBox = new QCheckBox(widget);
    gridCheckBox->setText(QStringLiteral("Show grid"));
    gridCheckBox->setChecked(true);

    QCheckBox *smoothCheckBox = new QCheckBox(widget);
    smoothCheckBox->setText(QStringLiteral("Smooth bars"));
    smoothCheckBox->setChecked(false);

    QCheckBox *seriesCheckBox = new QCheckBox(widget);
    seriesCheckBox->setText(QStringLiteral("Show second series"));
    seriesCheckBox->setChecked(false);

    QCheckBox *reverseValueAxisCheckBox = new QCheckBox(widget);
    reverseValueAxisCheckBox->setText(QStringLiteral("Reverse value axis"));
    reverseValueAxisCheckBox->setChecked(false);

    QCheckBox *reflectionCheckBox = new QCheckBox(widget);
    reflectionCheckBox->setText(QStringLiteral("Show reflections"));
    reflectionCheckBox->setChecked(false);

    QCheckBox *axisTitlesVisibleCB = new QCheckBox(widget);
    axisTitlesVisibleCB->setText(QStringLiteral("Axis titles visible"));
    axisTitlesVisibleCB->setChecked(true);

    QCheckBox *axisTitlesFixedCB = new QCheckBox(widget);
    axisTitlesFixedCB->setText(QStringLiteral("Axis titles fixed"));
    axisTitlesFixedCB->setChecked(true);

    vLayout->addWidget(backgroundCheckBox);
    vLayout->addWidget(gridCheckBox);
    vLayout->addWidget(smoothCheckBox);
    vLayout->addWidget(reflectionCheckBox);
    vLayout->addWidget(seriesCheckBox);
    vLayout->addWidget(reverseValueAxisCheckBox);
    vLayout->addWidget(axisTitlesVisibleCB);
    vLayout->addWidget(axisTitlesFixedCB);
    //! [显示效果开关复选框]
    //! [下拉菜单]
    QComboBox *themeList = new QComboBox(widget);
    themeList->addItem(QStringLiteral("Qt"));
    themeList->addItem(QStringLiteral("Primary Colors"));
    themeList->addItem(QStringLiteral("Digia"));
    themeList->addItem(QStringLiteral("Stone Moss"));
    themeList->addItem(QStringLiteral("Army Blue"));
    themeList->addItem(QStringLiteral("Retro"));
    themeList->addItem(QStringLiteral("Ebony"));
    themeList->addItem(QStringLiteral("Isabelle"));
    themeList->setCurrentIndex(0);

    QComboBox *barStyleList = new QComboBox(widget);
    barStyleList->addItem(QStringLiteral("Bar"), int(QAbstract3DSeries::MeshBar));
    barStyleList->addItem(QStringLiteral("Pyramid"), int(QAbstract3DSeries::MeshPyramid));
    barStyleList->addItem(QStringLiteral("Cone"), int(QAbstract3DSeries::MeshCone));
    barStyleList->addItem(QStringLiteral("Cylinder"), int(QAbstract3DSeries::MeshCylinder));
    barStyleList->addItem(QStringLiteral("Bevel bar"), int(QAbstract3DSeries::MeshBevelBar));
    barStyleList->addItem(QStringLiteral("Sphere"), int(QAbstract3DSeries::MeshSphere));
    barStyleList->setCurrentIndex(4);

    QComboBox *selectionModeList = new QComboBox(widget);
    selectionModeList->addItem(QStringLiteral("None"),
                               int(QAbstract3DGraph::SelectionNone));
    selectionModeList->addItem(QStringLiteral("Bar"),
                               int(QAbstract3DGraph::SelectionItem));
    selectionModeList->addItem(QStringLiteral("Row"),
                               int(QAbstract3DGraph::SelectionRow));
    selectionModeList->addItem(QStringLiteral("Bar and Row"),
                               int(QAbstract3DGraph::SelectionItemAndRow));
    selectionModeList->addItem(QStringLiteral("Column"),
                               int(QAbstract3DGraph::SelectionColumn));
    selectionModeList->addItem(QStringLiteral("Bar and Column"),
                               int(QAbstract3DGraph::SelectionItemAndColumn));
    selectionModeList->addItem(QStringLiteral("Row and Column"),
                               int(QAbstract3DGraph::SelectionRowAndColumn));
    selectionModeList->addItem(QStringLiteral("Bar, Row and Column"),
                               int(QAbstract3DGraph::SelectionItemRowAndColumn));
    selectionModeList->addItem(QStringLiteral("Slice into Row"),
                               int(QAbstract3DGraph::SelectionSlice | QAbstract3DGraph::SelectionRow));
    selectionModeList->addItem(QStringLiteral("Slice into Row and Item"),
                               int(QAbstract3DGraph::SelectionSlice | QAbstract3DGraph::SelectionItemAndRow));
    selectionModeList->addItem(QStringLiteral("Slice into Column"),
                               int(QAbstract3DGraph::SelectionSlice | QAbstract3DGraph::SelectionColumn));
    selectionModeList->addItem(QStringLiteral("Slice into Column and Item"),
                               int(QAbstract3DGraph::SelectionSlice | QAbstract3DGraph::SelectionItemAndColumn));
    selectionModeList->addItem(QStringLiteral("Multi: Bar, Row, Col"),
                               int(QAbstract3DGraph::SelectionItemRowAndColumn
                                   | QAbstract3DGraph::SelectionMultiSeries));
    selectionModeList->addItem(QStringLiteral("Multi, Slice: Row, Item"),
                               int(QAbstract3DGraph::SelectionSlice | QAbstract3DGraph::SelectionItemAndRow
                                   | QAbstract3DGraph::SelectionMultiSeries));
    selectionModeList->addItem(QStringLiteral("Multi, Slice: Col, Item"),
                               int(QAbstract3DGraph::SelectionSlice | QAbstract3DGraph::SelectionItemAndColumn
                                   | QAbstract3DGraph::SelectionMultiSeries));
    selectionModeList->setCurrentIndex(1);

    QFontComboBox *fontList = new QFontComboBox(widget);
    fontList->setCurrentFont(QFont("Times New Roman"));

    QComboBox *shadowQuality = new QComboBox(widget);
    shadowQuality->addItem(QStringLiteral("None"));
    shadowQuality->addItem(QStringLiteral("Low"));
    shadowQuality->addItem(QStringLiteral("Medium"));
    shadowQuality->addItem(QStringLiteral("High"));
    shadowQuality->addItem(QStringLiteral("Low Soft"));
    shadowQuality->addItem(QStringLiteral("Medium Soft"));
    shadowQuality->addItem(QStringLiteral("High Soft"));
    shadowQuality->setCurrentIndex(5);

    QComboBox *rangeList = new QComboBox(widget);
    rangeList->addItem(QStringLiteral("2006"));
    rangeList->addItem(QStringLiteral("2007"));
    rangeList->addItem(QStringLiteral("2008"));
    rangeList->addItem(QStringLiteral("2009"));
    rangeList->addItem(QStringLiteral("2010"));
    rangeList->addItem(QStringLiteral("2011"));
    rangeList->addItem(QStringLiteral("2012"));
    rangeList->addItem(QStringLiteral("2013"));
    rangeList->addItem(QStringLiteral("All"));
    rangeList->setCurrentIndex(8);

    vLayout->addWidget(new QLabel(QStringLiteral("Show year")));
    vLayout->addWidget(rangeList);
    vLayout->addWidget(new QLabel(QStringLiteral("Change bar style")));
    vLayout->addWidget(barStyleList);
    vLayout->addWidget(new QLabel(QStringLiteral("Change selection mode")));
    vLayout->addWidget(selectionModeList);
    vLayout->addWidget(new QLabel(QStringLiteral("Change theme")));
    vLayout->addWidget(themeList);
    vLayout->addWidget(new QLabel(QStringLiteral("Adjust shadow quality")));
    vLayout->addWidget(shadowQuality);
    vLayout->addWidget(new QLabel(QStringLiteral("Change font")));
    vLayout->addWidget(fontList);
    //! [下拉菜单]
    //! [文字显示slider]
    QSlider *fontSizeSlider = new QSlider(Qt::Horizontal, widget);
    fontSizeSlider->setTickInterval(10);
    fontSizeSlider->setTickPosition(QSlider::TicksBelow);
    fontSizeSlider->setMinimum(1);
    fontSizeSlider->setValue(30);
    fontSizeSlider->setMaximum(100);

    QSlider *axisLabelRotationSlider = new QSlider(Qt::Horizontal, widget);
    axisLabelRotationSlider->setTickInterval(10);
    axisLabelRotationSlider->setTickPosition(QSlider::TicksBelow);
    axisLabelRotationSlider->setMinimum(0);
    axisLabelRotationSlider->setValue(30);
    axisLabelRotationSlider->setMaximum(90);

    vLayout->addWidget(new QLabel(QStringLiteral("Adjust font size")));
    vLayout->addWidget(fontSizeSlider);
    vLayout->addWidget(new QLabel(QStringLiteral("Axis label rotation")));
    vLayout->addWidget(axisLabelRotationSlider, 1, Qt::AlignTop);
    //![文字显示slider]

显示效果如下(目前图形和控件还没有建立联系):
QT5.14.2自带Examples:Bars_第4张图片
下面我们将添加GraphModifier类。设置图形效果,为图形添加数据。

main函数3(创建modifier并建立联系)

    //! [创建modifier并建立联系]
    GraphModifier *modifier = new GraphModifier(widgetgraph);
    QObject::connect(rotationSliderX, &QSlider::valueChanged, modifier, &GraphModifier::rotateX);
    QObject::connect(rotationSliderY, &QSlider::valueChanged, modifier, &GraphModifier::rotateY);

    QObject::connect(labelButton, &QPushButton::clicked, modifier,
                     &GraphModifier::changeLabelBackground);
    QObject::connect(cameraButton, &QPushButton::clicked, modifier,
                     &GraphModifier::changePresetCamera);
    QObject::connect(zoomToSelectedButton, &QPushButton::clicked, modifier,
                     &GraphModifier::zoomToSelectedBar);

    QObject::connect(backgroundCheckBox, &QCheckBox::stateChanged, modifier,
                     &GraphModifier::setBackgroundEnabled);
    QObject::connect(gridCheckBox, &QCheckBox::stateChanged, modifier,
                     &GraphModifier::setGridEnabled);
    QObject::connect(smoothCheckBox, &QCheckBox::stateChanged, modifier,
                     &GraphModifier::setSmoothBars);
    QObject::connect(seriesCheckBox, &QCheckBox::stateChanged, modifier,
                     &GraphModifier::setSeriesVisibility);
    QObject::connect(reverseValueAxisCheckBox, &QCheckBox::stateChanged, modifier,
                     &GraphModifier::setReverseValueAxis);
    QObject::connect(reflectionCheckBox, &QCheckBox::stateChanged, modifier,
                     &GraphModifier::setReflection);

    QObject::connect(modifier, &GraphModifier::backgroundEnabledChanged,
                     backgroundCheckBox, &QCheckBox::setChecked);
    QObject::connect(modifier, &GraphModifier::gridEnabledChanged,
                     gridCheckBox, &QCheckBox::setChecked);

    QObject::connect(rangeList, SIGNAL(currentIndexChanged(int)), modifier,
                     SLOT(changeRange(int)));

    QObject::connect(barStyleList, SIGNAL(currentIndexChanged(int)), modifier,
                     SLOT(changeStyle(int)));

    QObject::connect(selectionModeList, SIGNAL(currentIndexChanged(int)), modifier,
                     SLOT(changeSelectionMode(int)));

    QObject::connect(themeList, SIGNAL(currentIndexChanged(int)), modifier,
                     SLOT(changeTheme(int)));

    QObject::connect(shadowQuality, SIGNAL(currentIndexChanged(int)), modifier,
                     SLOT(changeShadowQuality(int)));

    QObject::connect(modifier, &GraphModifier::shadowQualityChanged, shadowQuality,
                     &QComboBox::setCurrentIndex);
    QObject::connect(widgetgraph, &Q3DBars::shadowQualityChanged, modifier,
                     &GraphModifier::shadowQualityUpdatedByVisual);

    QObject::connect(fontSizeSlider, &QSlider::valueChanged, modifier,
                     &GraphModifier::changeFontSize);
    QObject::connect(fontList, &QFontComboBox::currentFontChanged, modifier,
                     &GraphModifier::changeFont);

    QObject::connect(modifier, &GraphModifier::fontSizeChanged, fontSizeSlider,
                     &QSlider::setValue);
    QObject::connect(modifier, &GraphModifier::fontChanged, fontList,
                     &QFontComboBox::setCurrentFont);

    QObject::connect(axisTitlesVisibleCB, &QCheckBox::stateChanged, modifier,
                     &GraphModifier::setAxisTitleVisibility);
    QObject::connect(axisTitlesFixedCB, &QCheckBox::stateChanged, modifier,
                     &GraphModifier::setAxisTitleFixed);
    QObject::connect(axisLabelRotationSlider, &QSlider::valueChanged, modifier,
                     &GraphModifier::changeLabelRotation);
    //! [创建modifier并建立联系]

GraphModifier定义

#ifndef GRAPHMODIFIER_H
#define GRAPHMODIFIER_H

#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 

using namespace QtDataVisualization;

class GraphModifier : public QObject
{
     
    Q_OBJECT
public:
    explicit GraphModifier(Q3DBars *bargraph);
    //该析构函数在本示例中可以省略
    //~GraphModifier();

    void resetTemperatureData();
    void changePresetCamera();
    void changeLabelBackground();
    void changeFont(const QFont &font);
    void changeFontSize(int fontsize);
    void rotateX(int rotation);
    void rotateY(int rotation);
    void setBackgroundEnabled(int enabled);
    void setGridEnabled(int enabled);
    void setSmoothBars(int smooth);
    void setSeriesVisibility(int enabled);
    void setReverseValueAxis(int enabled);
    void setReflection(bool enabled);

public Q_SLOTS:
    void changeRange(int range);
    void changeStyle(int style);
    void changeSelectionMode(int selectionMode);
    void changeTheme(int theme);
    void changeShadowQuality(int quality);
    void shadowQualityUpdatedByVisual(QAbstract3DGraph::ShadowQuality shadowQuality);
    void changeLabelRotation(int rotation);
    void setAxisTitleVisibility(bool enabled);
    void setAxisTitleFixed(bool enabled);
    void zoomToSelectedBar();

Q_SIGNALS:
    void shadowQualityChanged(int quality);
    void backgroundEnabledChanged(bool enabled);
    void gridEnabledChanged(bool enabled);
    void fontChanged(QFont font);
    void fontSizeChanged(int size);

private:
    Q3DBars *m_graph;
    float m_xRotation;
    float m_yRotation;
    int m_fontSize;
    int m_segments;
    int m_subSegments;
    float m_minval;
    float m_maxval;
    QStringList m_months;
    QStringList m_years;
    QValue3DAxis *m_temperatureAxis;
    QCategory3DAxis *m_yearAxis;
    QCategory3DAxis *m_monthAxis;
    QBar3DSeries *m_primarySeries;
    QBar3DSeries *m_secondarySeries;
    QAbstract3DSeries::Mesh m_barMesh;
    bool m_smooth;
    QPropertyAnimation m_animationCameraX;
    QPropertyAnimation m_animationCameraY;
    QPropertyAnimation m_animationCameraZoom;
    QPropertyAnimation m_animationCameraTarget;
    float m_defaultAngleX;
    float m_defaultAngleY;
    float m_defaultZoom;
    QVector3D m_defaultTarget;
};

#endif

GraphModifier实现1(框架搭建)

#include "graphmodifier.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace QtDataVisualization;
const QString celsiusString = QString(QChar(0xB0)) + "C";
//! [0]
GraphModifier::GraphModifier(Q3DBars *bargraph)
    : m_graph(bargraph),
    m_xRotation(0.0f),
    m_yRotation(0.0f),
    m_fontSize(30),
    m_segments(4),
    m_subSegments(3),
    m_minval(-20.0f),
    m_maxval(20.0f),
    m_temperatureAxis(new QValue3DAxis),
    m_yearAxis(new QCategory3DAxis),
    m_monthAxis(new QCategory3DAxis),
    m_primarySeries(new QBar3DSeries),
    m_secondarySeries(new QBar3DSeries),
    m_barMesh(QAbstract3DSeries::MeshBevelBar),
    m_smooth(false)
{
     
    m_months << "January" << "February" << "March" << "April" << "May" << "June" << "July" << "August" << "September" << "October" << "November" << "December";
    m_years << "2006" << "2007" << "2008" << "2009" << "2010" << "2011" << "2012" << "2013";

    //![轴设置]
    //OpenGL:Y轴:m_temperatureAxis
    m_temperatureAxis->setTitle("平均温度");

    //要绘制的网格线的数量按以下公式计算:线段*子线段+1。预设默认值为5。
    //这里分成4分,需要五根线
    m_temperatureAxis->setSegmentCount(4);
    //这里分成3份,需要两根线。因为已经有头尾两根线
    m_temperatureAxis->setSubSegmentCount(3);
    m_temperatureAxis->setRange(m_minval, m_maxval);//OpenGL:Y轴范围-20到20度
    m_temperatureAxis->setLabelFormat(QString(QStringLiteral("%.1f ") + celsiusString));
    //留相机角度更改时,标签可以自动旋转的最大角度。
    m_temperatureAxis->setLabelAutoRotation(30.0f);
    m_temperatureAxis->setTitleVisible(true);
    //OpenGL:Z、X轴:m_yearAxis、m_monthAxis
    m_yearAxis->setTitle("年");
    m_yearAxis->setLabelAutoRotation(30.0f);
    m_yearAxis->setTitleVisible(true);
    m_monthAxis->setTitle("月");
    m_monthAxis->setLabelAutoRotation(30.0f);
    m_monthAxis->setTitleVisible(true);

    m_graph->setValueAxis(m_temperatureAxis);
    m_graph->setRowAxis(m_yearAxis);
    m_graph->setColumnAxis(m_monthAxis);
    //![轴设置]

    //![设置图形的一些视觉效果]
    m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualitySoftMedium);
    m_graph->activeTheme()->setBackgroundEnabled(false);
    m_graph->activeTheme()->setFont(QFont("Times New Roman", m_fontSize));
    m_graph->activeTheme()->setLabelBackgroundEnabled(true);
    //值根据一个数据序列决定缩放比例
    //如果设置为true,则条间距将仅正确应用于Z轴。
    m_graph->setMultiSeriesUniform(true);
    //![设置图形的一些视觉效果]
    //![数据设置]
    m_primarySeries->setItemLabelFormat(QStringLiteral("奥卢 - @colLabel @rowLabel: @valueLabel"));
    m_primarySeries->setMesh(QAbstract3DSeries::MeshBevelBar);
    m_primarySeries->setMeshSmooth(false);

    m_secondarySeries->setItemLabelFormat(QStringLiteral("赫尔辛基 - @colLabel @rowLabel: @valueLabel"));
    m_secondarySeries->setMesh(QAbstract3DSeries::MeshBevelBar);
    m_secondarySeries->setMeshSmooth(false);
    //初始状态不显示
    m_secondarySeries->setVisible(false);

    m_graph->addSeries(m_primarySeries);
    m_graph->addSeries(m_secondarySeries);
    //![数据设置]
    //设置相机角度:
    //与UI中的camera angle change按钮方法一样
    changePresetCamera();

    resetTemperatureData();
    // 设置用于缩放到选定栏的属性动画
    //! [动画设置]
    Q3DCamera *camera = m_graph->scene()->activeCamera();
    m_defaultAngleX = camera->xRotation();
    m_defaultAngleY = camera->yRotation();
    m_defaultZoom = camera->zoomLevel();
    m_defaultTarget = camera->target();

    m_animationCameraX.setTargetObject(camera);
    m_animationCameraY.setTargetObject(camera);
    m_animationCameraZoom.setTargetObject(camera);
    m_animationCameraTarget.setTargetObject(camera);

    m_animationCameraX.setPropertyName("xRotation");
    m_animationCameraY.setPropertyName("yRotation");
    m_animationCameraZoom.setPropertyName("zoomLevel");
    m_animationCameraTarget.setPropertyName("target");

    int duration = 1700;
    m_animationCameraX.setDuration(duration);
    m_animationCameraY.setDuration(duration);
    m_animationCameraZoom.setDuration(duration);
    m_animationCameraTarget.setDuration(duration);

    //动画除了起始状态,最终状态,还可以插入一个中间状态
    // 缩放总是先缩小到图形上方,然后再放大
    //在动画进行到30%的时候到达下面的状态
    qreal zoomOutFraction = 0.3;
    m_animationCameraX.setKeyValueAt(zoomOutFraction, QVariant::fromValue(0.0f));
    //顶视图
    m_animationCameraY.setKeyValueAt(zoomOutFraction, QVariant::fromValue(90.0f));
    //缩小一半
    m_animationCameraZoom.setKeyValueAt(zoomOutFraction, QVariant::fromValue(50.0f));
    m_animationCameraTarget.setKeyValueAt(zoomOutFraction,
                                  QVariant::fromValue(QVector3D(0.0f, 0.0f, 0.0f)));0.0f)));
    //! [动画设置]
}
//! [0]


void GraphModifier::resetTemperatureData()
{
     

}

void GraphModifier::changeRange(int range)
{
     

}

void GraphModifier::changeStyle(int style)
{
     

}

void GraphModifier::changePresetCamera()
{
     

}

void GraphModifier::changeTheme(int theme)
{
     

}

void GraphModifier::changeLabelBackground()
{
     

}

void GraphModifier::changeSelectionMode(int selectionMode)
{
     

}

void GraphModifier::changeFont(const QFont &font)
{
     

}

void GraphModifier::changeFontSize(int fontsize)
{
     

}

void GraphModifier::shadowQualityUpdatedByVisual(QAbstract3DGraph::ShadowQuality sq)
{
     

}

void GraphModifier::changeLabelRotation(int rotation)
{
     

}

void GraphModifier::setAxisTitleVisibility(bool enabled)
{
     

}

void GraphModifier::setAxisTitleFixed(bool enabled)
{
     

}

//! [11]
void GraphModifier::zoomToSelectedBar()
{
     

}

void GraphModifier::changeShadowQuality(int quality)
{
     

}


void GraphModifier::rotateX(int rotation)
{
     

}

void GraphModifier::rotateY(int rotation)
{
     

}

void GraphModifier::setBackgroundEnabled(int enabled)
{
     

}

void GraphModifier::setGridEnabled(int enabled)
{
     

}

void GraphModifier::setSmoothBars(int smooth)
{
     

}

void GraphModifier::setSeriesVisibility(int enabled)
{
     

}

void GraphModifier::setReverseValueAxis(int enabled)
{
     

}

void GraphModifier::setReflection(bool enabled)
{
     

}

显示效果:
QT5.14.2自带Examples:Bars_第5张图片

GraphModifier实现2(changePresetCamera,观察点设置)

void GraphModifier::changePresetCamera()
{
     
	//如果当前有动画正在运行则停止播放
    m_animationCameraX.stop();
    m_animationCameraY.stop();
    m_animationCameraZoom.stop();
    m_animationCameraTarget.stop();

    //如果动画改变了摄像机目标,则还原摄像机目标
    m_graph->scene()->activeCamera()->setTarget(QVector3D(0.0f, 0.0f, 0.0f));
    //当前活动的相机预设,从正前方看一个很好的位置和角度
    //注意这里是static,配合下面if里的++preset,实现观察点的遍历
    static int preset = Q3DCamera::CameraPresetFront;

    m_graph->scene()->activeCamera()->setCameraPreset((Q3DCamera::CameraPreset)preset);
    //枚举量的一个循环, CameraPresetFrontLow 的值是0,CameraPresetDirectlyBelow的值为最大值
    if (++preset > Q3DCamera::CameraPresetDirectlyBelow)
        preset = Q3DCamera::CameraPresetFrontLow;
}

该函数不但可以设置初始角度,还已经在main函数里设置了connection,现在可以点击按钮观察效果了。该函数的效果演示,我们在添加完数据后一起验收。

GraphModifier实现3(resetTemperatureData,添加数据)

void GraphModifier::resetTemperatureData()
{
     
    // 设置数据8年12个月
    static const float tempOulu[8][12] = {
     
        {
     -6.7f, -11.7f, -9.7f, 3.3f, 9.2f, 14.0f, 16.3f, 17.8f, 10.2f, 2.1f, -2.6f, -0.3f},    // 2006
        {
     -6.8f, -13.3f, 0.2f, 1.5f, 7.9f, 13.4f, 16.1f, 15.5f, 8.2f, 5.4f, -2.6f, -0.8f},      // 2007
        {
     -4.2f, -4.0f, -4.6f, 1.9f, 7.3f, 12.5f, 15.0f, 12.8f, 7.6f, 5.1f, -0.9f, -1.3f},      // 2008
        {
     -7.8f, -8.8f, -4.2f, 0.7f, 9.3f, 13.2f, 15.8f, 15.5f, 11.2f, 0.6f, 0.7f, -8.4f},      // 2009
        {
     -14.4f, -12.1f, -7.0f, 2.3f, 11.0f, 12.6f, 18.8f, 13.8f, 9.4f, 3.9f, -5.6f, -13.0f},  // 2010
        {
     -9.0f, -15.2f, -3.8f, 2.6f, 8.3f, 15.9f, 18.6f, 14.9f, 11.1f, 5.3f, 1.8f, -0.2f},     // 2011
        {
     -8.7f, -11.3f, -2.3f, 0.4f, 7.5f, 12.2f, 16.4f, 14.1f, 9.2f, 3.1f, 0.3f, -12.1f},     // 2012
        {
     -7.9f, -5.3f, -9.1f, 0.8f, 11.6f, 16.6f, 15.9f, 15.5f, 11.2f, 4.0f, 0.1f, -1.9f}      // 2013
    };

    static const float tempHelsinki[8][12] = {
     
        {
     -3.7f, -7.8f, -5.4f, 3.4f, 10.7f, 15.4f, 18.6f, 18.7f, 14.3f, 8.5f, 2.9f, 4.1f},      // 2006
        {
     -1.2f, -7.5f, 3.1f, 5.5f, 10.3f, 15.9f, 17.4f, 17.9f, 11.2f, 7.3f, 1.1f, 0.5f},       // 2007
        {
     -0.6f, 1.2f, 0.2f, 6.3f, 10.2f, 13.8f, 18.1f, 15.1f, 10.1f, 9.4f, 2.5f, 0.4f},        // 2008
        {
     -2.9f, -3.5f, -0.9f, 4.7f, 10.9f, 14.0f, 17.4f, 16.8f, 13.2f, 4.1f, 2.6f, -2.3f},     // 2009
        {
     -10.2f, -8.0f, -1.9f, 6.6f, 11.3f, 14.5f, 21.0f, 18.8f, 12.6f, 6.1f, -0.5f, -7.3f},   // 2010
        {
     -4.4f, -9.1f, -2.0f, 5.5f, 9.9f, 15.6f, 20.8f, 17.8f, 13.4f, 8.9f, 3.6f, 1.5f},       // 2011
        {
     -3.5f, -3.2f, -0.7f, 4.0f, 11.1f, 13.4f, 17.3f, 15.8f, 13.1f, 6.4f, 4.1f, -5.1f},     // 2012
        {
     -4.8f, -1.8f, -5.0f, 2.9f, 12.8f, 17.2f, 18.0f, 17.1f, 12.5f, 7.5f, 4.5f, 2.3f}       // 2013
    };

    // 创建 QBarDataArray对象
    QBarDataArray *dataSet = new QBarDataArray;
    QBarDataArray *dataSet2 = new QBarDataArray;
    QBarDataRow *dataRow;
    QBarDataRow *dataRow2;

    dataSet->reserve(m_years.size());
    for (int year = 0; year < m_years.size(); year++) {
     
        // 创建数据行
        dataRow = new QBarDataRow(m_months.size());
        dataRow2 = new QBarDataRow(m_months.size());
        for (int month = 0; month < m_months.size(); month++) {
     
            // 向行中添加数据
            (*dataRow)[month].setValue(tempOulu[year][month]);
            (*dataRow2)[month].setValue(tempHelsinki[year][month]);
        }
        // 将行添加到QBarDataArray对象
        dataSet->append(dataRow);
        dataSet2->append(dataRow2);
    }

    // 将数据添加到数据代理(数据代理取得它的所有权)
    m_primarySeries->dataProxy()->resetArray(dataSet, m_years, m_months);
    m_secondarySeries->dataProxy()->resetArray(dataSet2, m_years, m_months);
}

QT5.14.2自带Examples:Bars_第6张图片

GraphModifier实现4(滑动条控制旋转角度)

void GraphModifier::rotateX(int rotation)
{
     
    m_xRotation = rotation;
    m_graph->scene()->activeCamera()->setCameraPosition(m_xRotation, m_yRotation);
}

void GraphModifier::rotateY(int rotation)
{
     
    m_yRotation = rotation;
    m_graph->scene()->activeCamera()->setCameraPosition(m_xRotation, m_yRotation);
}

QT5.14.2自带Examples:Bars_第7张图片

GraphModifier实现5(按钮效果)

void GraphModifier::changeLabelBackground()
{
     
    m_graph->activeTheme()->setLabelBackgroundEnabled(
    	!m_graph->activeTheme()->isLabelBackgroundEnabled());
}

//! [放大选中区域]
//1、设置动画初始状态
//2、设置动画结束状态(这部分是核心,需要更加观察目标找到合适的观察方位)
//3、启动动画
void GraphModifier::zoomToSelectedBar()
{
     
    m_animationCameraX.stop();
    m_animationCameraY.stop();
    m_animationCameraZoom.stop();
    m_animationCameraTarget.stop();

    Q3DCamera *camera = m_graph->scene()->activeCamera();
    float currentX = camera->xRotation();
    float currentY = camera->yRotation();
    float currentZoom = camera->zoomLevel();
    QVector3D currentTarget = camera->target();
    //! [动画初始状态]
    m_animationCameraX.setStartValue(QVariant::fromValue(currentX));
    m_animationCameraY.setStartValue(QVariant::fromValue(currentY));
    m_animationCameraZoom.setStartValue(QVariant::fromValue(currentZoom));
    m_animationCameraTarget.setStartValue(QVariant::fromValue(currentTarget));
    //! [动画初始状态]
    //selectedSeries返回所选栏归属的序列
    QPoint selectedBar = m_graph->selectedSeries()
                             ? m_graph->selectedSeries()->selectedBar()//返回选中的项目
                             : QBar3DSeries::invalidSelectionPosition();

    if (selectedBar != QBar3DSeries::invalidSelectionPosition()) {
     
        //! [在轴范围内标准化选定的条位置,以确定目标坐标]
        //OpenGL的坐标系下面是Z和X周,上面是Y
        QVector3D endTarget;
        float xMin = m_graph->columnAxis()->min();
        float xRange = m_graph->columnAxis()->max() - xMin;
        float zMin = m_graph->rowAxis()->min();
        float zRange = m_graph->rowAxis()->max() - zMin;
        //标准化到-1到1之间
        endTarget.setX((selectedBar.y() - xMin) / xRange * 2.0f - 1.0f);
        endTarget.setZ((selectedBar.x() - zMin) / zRange * 2.0f - 1.0f);
        //! [在轴范围内标准化选定的条位置,以确定目标坐标]

        //! [旋转相机使其始终指向图形中心]
        //水平旋转
        qreal endAngleX = 90.0 - qRadiansToDegrees(qAtan(qreal(endTarget.z() / endTarget.x())));
        //角度为正是逆时针转置。所以如果x为负数,则正常旋转0-180度即可。
        //如果x为正数,需要顺时针选择0-180度,否则到不了屏幕正前方。
        if (endTarget.x() > 0.0f)
            endAngleX -= 180.0f;
        float barValue = m_graph->selectedSeries()->dataProxy()->itemAt(selectedBar.x(),
                                                                        selectedBar.y())->value();
        //观察value的角度为30°,值为负数则为-30°,Rotate Vertically
        float endAngleY = barValue >= 0.0f ? 30.0f : -30.0f;
        if (m_graph->valueAxis()->reversed())
            endAngleY *= -1.0f;
        //! [旋转相机使其始终指向图形中心]

        m_animationCameraX.setEndValue(QVariant::fromValue(float(endAngleX)));
        m_animationCameraY.setEndValue(QVariant::fromValue(endAngleY));
        //放大到默认的2.5倍
        m_animationCameraZoom.setEndValue(QVariant::fromValue(250));
        m_animationCameraTarget.setEndValue(QVariant::fromValue(endTarget));
    } else {
     
        // 没有选择栏,回到初始状态
        m_animationCameraX.setEndValue(QVariant::fromValue(m_defaultAngleX));
        m_animationCameraY.setEndValue(QVariant::fromValue(m_defaultAngleY));
        m_animationCameraZoom.setEndValue(QVariant::fromValue(m_defaultZoom));
        m_animationCameraTarget.setEndValue(QVariant::fromValue(m_defaultTarget));
    }

    m_animationCameraX.start();
    m_animationCameraY.start();
    m_animationCameraZoom.start();
    m_animationCameraTarget.start();
}
//! [放大选中区域]

QT5.14.2自带Examples:Bars_第8张图片
QT5.14.2自带Examples:Bars_第9张图片

QT5.14.2自带Examples:Bars_第10张图片

GraphModifier实现6(复选框特效开关)

QT5.14.2自带Examples:Bars_第11张图片
这部分代码只是简单的设置特效的开关,把程序运行起来对照观察即可,这里就不详细描述了。

void GraphModifier::setBackgroundEnabled(int enabled)
{
     
    m_graph->activeTheme()->setBackgroundEnabled(bool(enabled));
}

void GraphModifier::setGridEnabled(int enabled)
{
     
    m_graph->activeTheme()->setGridEnabled(bool(enabled));
}

void GraphModifier::setSmoothBars(int smooth)
{
     
    m_smooth = bool(smooth);
    m_primarySeries->setMeshSmooth(m_smooth);
    m_secondarySeries->setMeshSmooth(m_smooth);
}

void GraphModifier::setSeriesVisibility(int enabled)
{
     
    m_secondarySeries->setVisible(bool(enabled));
}

void GraphModifier::setReverseValueAxis(int enabled)
{
     
    m_graph->valueAxis()->setReversed(enabled);
}

void GraphModifier::setReflection(bool enabled)
{
     
    m_graph->setReflection(enabled);
}

void GraphModifier::setAxisTitleVisibility(bool enabled)
{
     
    m_temperatureAxis->setTitleVisible(enabled);
    m_monthAxis->setTitleVisible(enabled);
    m_yearAxis->setTitleVisible(enabled);
}

void GraphModifier::setAxisTitleFixed(bool enabled)
{
     
    m_temperatureAxis->setTitleFixed(enabled);
    m_monthAxis->setTitleFixed(enabled);
    m_yearAxis->setTitleFixed(enabled);
}

GraphModifier实现7(其他控件)

QT5.14.2自带Examples:Bars_第12张图片

//show year
void GraphModifier::changeRange(int range)
{
     
    if (range >= m_years.count())
        m_yearAxis->setRange(0, m_years.count() - 1);
    else
        m_yearAxis->setRange(range, range);
}
//change bar style
void GraphModifier::changeStyle(int style)
{
     
    //返回指向发送信号的对象的指针,没有则返回nullptr。
    QComboBox *comboBox = qobject_cast<QComboBox *>(sender());
    if (comboBox) {
     
        //mesh:由数据(通常指的是顶点数据)构成的一个三维模型
        //为数据选择一个形状(内置的mesh类型)
        m_barMesh = QAbstract3DSeries::Mesh(comboBox->itemData(style).toInt());
        m_primarySeries->setMesh(m_barMesh);
        m_secondarySeries->setMesh(m_barMesh);
    }
}
//选择模式,选择一个bar?还是一行?等等
void GraphModifier::changeSelectionMode(int selectionMode)
{
     
    QComboBox *comboBox = qobject_cast<QComboBox *>(sender());
    if (comboBox) {
     
        int flags = comboBox->itemData(selectionMode).toInt();
        m_graph->setSelectionMode(QAbstract3DGraph::SelectionFlags(flags));
    }
}

void GraphModifier::changeTheme(int theme)
{
     
    Q3DTheme *currentTheme = m_graph->activeTheme();
    currentTheme->setType(Q3DTheme::Theme(theme));
    emit backgroundEnabledChanged(currentTheme->isBackgroundEnabled());
    emit gridEnabledChanged(currentTheme->isGridEnabled());
    emit fontChanged(currentTheme->font());
    emit fontSizeChanged(currentTheme->font().pointSize());
}


void GraphModifier::changeShadowQuality(int quality)
{
     
    QAbstract3DGraph::ShadowQuality sq = QAbstract3DGraph::ShadowQuality(quality);
    m_graph->setShadowQuality(sq);
    emit shadowQualityChanged(quality);
}

void GraphModifier::changeFont(const QFont &font)
{
     
    QFont newFont = font;
    m_graph->activeTheme()->setFont(newFont);
}

void GraphModifier::changeFontSize(int fontsize)
{
     
    m_fontSize = fontsize;
    QFont font = m_graph->activeTheme()->font();
    font.setPointSize(m_fontSize);
    m_graph->activeTheme()->setFont(font);
}

void GraphModifier::changeLabelRotation(int rotation)
{
     
    m_temperatureAxis->setLabelAutoRotation(float(rotation));
    m_monthAxis->setLabelAutoRotation(float(rotation));
    m_yearAxis->setLabelAutoRotation(float(rotation));
}


//这里好像没有用到,保持效果与控件的显示一致。
//具体实现方法查看main函数
void GraphModifier::shadowQualityUpdatedByVisual(QAbstract3DGraph::ShadowQuality sq)
{
     
    int quality = int(sq);

    emit shadowQualityChanged(quality);
}

该示例并不完整,还有需要改良的地方。例如旋转的控件与显示效果不一致,没有联动。在改变选择模式后,zoom to selected bar功能效果不对。理解了前面的内容,这些都可以自己实现。例如可以在main中加入以下代码,关联xRotate和yRotate控件和显示效果:

//也可以直接将显示效果与控件绑定,但我们这样更加灵活。
//示例中的阴影效果设置,也是用的同样的方法。
    QObject::connect(widgetgraph->scene()->activeCamera(), &Q3DCamera::xRotationChanged,
                     modifier, &GraphModifier::xRotateChanged);
    QObject::connect(modifier, &GraphModifier::xRotateChanged,
                     rotationSliderX,&QSlider::setValue);
    QObject::connect(widgetgraph->scene()->activeCamera(), &Q3DCamera::xRotationChanged,
                     modifier, &GraphModifier::xRotateChanged);
    QObject::connect(modifier, &GraphModifier::xRotateChanged,
                     rotationSliderX,&QSlider::setValue);

必须事先在GraphModifier类的头文件中给出xRotateChanged和yRotateChanged的声明,Q_SIGNALS无需给出实现代码。只是用来传递参数。

Q_SIGNALS:
    void xRotateChanged(int xRotate);
    void yRotateChanged(int yRotate);

这样我们就可以在需要改变选择值的时候,通过emit发出可。
注意:在本示例中,modifier对象的构造函数改变了旋转角度,旋转发生在connect建立之前。需要通过其他手段实现效果的一致,例如通过timer,一段时间后emit一个信号,执行一次后关闭timer。

你可能感兴趣的:(QT5.14.2自带Examples:Bars)