QT数据可视化框架编程实战之三维柱状图_补天云QT技术培训专家

QT数据可视化框架编程实战之三维柱状图_补天云QT技术培训专家

简介
本文将介绍QT数据可视化框架编程实战之三维柱状图可视化的运行效果以及具体实现代码。
(本文广泛参考了QT数据可视化框架的例程。)

正文

QT数据可视化框架编程实战:三维柱状图可视化运行效果

QT数据可视化框架编程实战之三维柱状图可视化的运行效果如下图所示。数据按照每年12个月,每月数据对应一个三维柱体。共三个坐标轴,水平方向的两个坐标轴分别是年份和月份;垂直方向一个坐标轴是收入。
在这里插入图片描述

演示视频如下所示:

QT数据可视化框架编程实战之三维柱状图 补天云QT技术培训专家

读者也可以访问这个链接观看演示视频:
QT数据可视化框架编程实战之三维柱状图 补天云QT技术培训专家

主程序实现C++代码

#include <QtGui/qguiapplication.h>
#include <QtQuick/qquickview.h>
#include <QtQml/qqmlengine.h>

int main(int argc, char *argv[])
{
    qputenv("QSG_RHI_BACKEND", "opengl");
    QGuiApplication app(argc, argv);

    QQuickView viewer;

    QString extraImportPath(QStringLiteral("%1/../../../../%2"));
    viewer.engine()->addImportPath(extraImportPath.arg(QGuiApplication::applicationDirPath(),
                                                       QString::fromLatin1("qml")));

    viewer.setTitle(QStringLiteral("Monthly income"));

    viewer.setSource(QUrl("qrc:/qml/qmlbars/main.qml"));
    viewer.setResizeMode(QQuickView::SizeRootObjectToView);
    viewer.setColor("black");
    viewer.show();

    return app.exec();
}

主场景 QML代码

main.qml文件:


import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtDataVisualization
import Qt.labs.qmlmodels

pragma ComponentBehavior: Bound

Item {
    id: mainview
    width: 1280
    height: 1024

    property int buttonLayoutHeight: 180
    property int currentRow
    state:  "landscape"

    Data {
        id: graphData
    }

    Axes {
        id: graphAxes
    }

    property Bar3DSeries selectedSeries
    selectedSeries: barSeries

    function handleSelectionChange(series, position) {
        if (position !== series.invalidSelectionPosition)
            selectedSeries = series;

        // Set tableView current row to selected bar
        var rowRole = series.dataProxy.rowLabels[position.x];
        var colRole;
        if (barGraph.columnAxis == graphAxes.total)
            colRole = "01";
        else
            colRole = series.dataProxy.columnLabels[position.y];
        var checkTimestamp = rowRole + "-" + colRole;

        if (currentRow === -1 || checkTimestamp !== graphData.model.get(currentRow).timestamp) {
            var totalRows = tableView.rows;
            for (var i = 0; i < totalRows; i++) {
                var modelTimestamp = graphData.model.get(i).timestamp;
                if (modelTimestamp === checkTimestamp) {
                    currentRow = i;
                    break;
                }
            }
        }
    }

    Item {
        id: dataView
        anchors.right: mainview.right
        anchors.bottom: mainview.bottom

        Bars3D {
            id: barGraph
            anchors.fill: parent
            shadowQuality: AbstractGraph3D.ShadowQualitySoftHigh
            selectionMode: AbstractGraph3D.SelectionItem
            theme: Theme3D {
                type: Theme3D.ThemeEbony
                labelBorderEnabled: true
                font.pointSize: 35
                labelBackgroundEnabled: true
                colorStyle: Theme3D.ColorStyleRangeGradient
                singleHighlightGradient: customGradient

                ColorGradient {
                    id: customGradient
                    ColorGradientStop { position: 1.0; color: "#FFFF00" }
                    ColorGradientStop { position: 0.0; color: "#808000" }
                }
            }
            barThickness: 0.7
            barSpacing: Qt.size(0.5, 0.5)
            barSpacingRelative: false
            scene.activeCamera.cameraPreset: Camera3D.CameraPresetIsometricLeftHigh
            columnAxis: graphAxes.column
            rowAxis: graphAxes.row
            valueAxis: graphAxes.value


            Bar3DSeries {
                id: barSeries
                itemLabelFormat: "Income, @colLabel, @rowLabel: @valueLabel"
                baseGradient: barGradient

                ItemModelBarDataProxy {
                    id: modelProxy
                    itemModel: graphData.model
                    rowRole: "timestamp"
                    columnRole: "timestamp"
                    valueRole: "income"
                    rowRolePattern: /^(\d\d\d\d).*$/
                    columnRolePattern: /^.*-(\d\d)$/
                    rowRoleReplace: "\\1"
                    columnRoleReplace: "\\1"
                    multiMatchBehavior: ItemModelBarDataProxy.MMBCumulative
                }
                //! [3]

                ColorGradient {
                    id: barGradient
                    ColorGradientStop { position: 1.0; color: "#00FF00" }
                    ColorGradientStop { position: 0.0; color: "#006000" }
                }

                onSelectedBarChanged: (position) => mainview.handleSelectionChange(barSeries,
                                                                                   position);
            }
        }
    }

    ColumnLayout {
        id: tableViewLayout

        anchors.top: parent.top
        anchors.left: parent.left

        HorizontalHeaderView {
            id: headerView
            readonly property var columnNames: ["Month", "Expenses", "Income"]

            syncView: tableView
            Layout.fillWidth: true
            delegate: Text {
                required property int index
                padding: 3
                text: headerView.columnNames[index]
                color: barGraph.theme.labelTextColor
                horizontalAlignment: Text.AlignHCenter
                verticalAlignment: Text.AlignVCenter
                elide: Text.ElideRight
            }
        }

        TableView {
            id: tableView
            Layout.fillWidth: true
            Layout.fillHeight: true

            reuseItems: false
            clip: true

            model: TableModel {
                id: tableModel
                TableModelColumn { display: "timestamp" }
                TableModelColumn { display: "expenses" }
                TableModelColumn { display: "income" }

                rows: graphData.modelAsJsArray
            }

            delegate: Rectangle {
                id: delegateRoot
                required property int row
                required property int column
                required property string display
                implicitHeight: 30
                implicitWidth: column === 0 ? tableView.width / 2 : tableView.width / 4
                color: row === mainview.currentRow ? barGraph.theme.gridLineColor
                                                   : barGraph.theme.windowColor
                border.color: row === mainview.currentRow ? barGraph.theme.labelTextColor
                                                          : barGraph.theme.gridLineColor
                border.width: 1
                MouseArea {
                    anchors.fill: parent
                    onClicked: mainview.currentRow = delegateRoot.row;
                }

                Text {
                    id: delegateText
                    anchors.verticalCenter: parent.verticalCenter
                    width: parent.width
                    anchors.leftMargin: 4
                    anchors.left: parent.left
                    anchors.right: parent.right
                    text: formattedText
                    property string formattedText: {
                        if (delegateRoot.column === 0) {
                            if (delegateRoot.display !== "") {
                                var pattern = /(\d\d\d\d)-(\d\d)/;
                                var matches = pattern.exec(delegateRoot.display);
                                var colIndex = parseInt(matches[2], 10) - 1;
                                return matches[1] + " - " + graphAxes.column.labels[colIndex];
                            }
                        } else {
                            return delegateRoot.display;
                        }
                    }
                    color: barGraph.theme.labelTextColor
                    horizontalAlignment: delegateRoot.column === 0 ? Text.AlignLeft
                                                                   : Text.AlignHCenter
                    elide: Text.ElideRight
                }
            }
        }
    }

    //! [2]
    onCurrentRowChanged: {
        var timestamp = graphData.model.get(mainview.currentRow).timestamp;
        var pattern = /(\d\d\d\d)-(\d\d)/;
        var matches = pattern.exec(timestamp);
        var rowIndex = modelProxy.rowCategoryIndex(matches[1]);
        var colIndex;
        if (barGraph.columnAxis == graphAxes.total)
            colIndex = 0 ;// Just one column when showing yearly totals
        else
            colIndex = modelProxy.columnCategoryIndex(matches[2]);
        if (selectedSeries.visible)
            mainview.selectedSeries.selectedBar = Qt.point(rowIndex, colIndex);
        else if (barSeries.visible)
            barSeries.selectedBar = Qt.point(rowIndex, colIndex);
        else
            secondarySeries.selectedBar = Qt.point(rowIndex, colIndex);
    }
    //! [2]



    states: [
        State  {
            name: "landscape"
            PropertyChanges {
                target: dataView
                width: mainview.width / 4 * 3
                height: mainview.height
            }
            PropertyChanges  {
                target: tableViewLayout
                height: mainview.height - buttonLayoutHeight
                anchors.right: dataView.left
                anchors.left: mainview.left
                anchors.bottom: undefined
            }
            PropertyChanges  {
                target: controlLayout
                width: mainview.width / 4
                height: buttonLayoutHeight
                anchors.top: tableViewLayout.bottom
                anchors.bottom: mainview.bottom
                anchors.left: mainview.left
                anchors.right: dataView.left
            }
        }
    ]
}

坐标轴QML代码

axes.qml文件:


import QtQuick
import QtDataVisualization

Item {
    property alias column: columnAxis
    property alias row: rowAxis
    property alias value: valueAxis
    property alias total: totalAxis

    // Custom labels for columns, since the data contains abbreviated month names.
    //! [0]
    CategoryAxis3D {
        id: columnAxis
        labels: ["January", "February", "March", "April", "May", "June",
            "July", "August", "September", "October", "November", "December"]
        labelAutoRotation: 30
    }
 
    CategoryAxis3D {
        id: totalAxis
        labels: ["Yearly total"]
        labelAutoRotation: 30
    }
    CategoryAxis3D {
        id: rowAxis
        labelAutoRotation: 30
    }

    ValueAxis3D {
        id: valueAxis
        min: 0
        max: 35
        labelFormat: "%.2f M\u20AC"
        title: "Monthly income"
        labelAutoRotation: 90
    }
}

数据模型定义 QML代码

data.qml文件:

import QtQuick
import QtQml.Models

Item {
    property alias model: dataModel

    property var modelAsJsArray: {
        var arr = [];
        for (var i = 0; i < dataModel.count; i++) {
            var row = dataModel.get(i);
            arr.push({
                         timestamp: row.timestamp,
                         expenses: row.expenses,
                         income: row.income
                     });
        }
        return arr;
    }

   ListModel {
        id: dataModel
        ListElement{ timestamp: "2016-01"; expenses: "-4";  income: "5" }
        ListElement{ timestamp: "2016-02"; expenses: "-5";  income: "6" }
        ListElement{ timestamp: "2016-03"; expenses: "-7";  income: "4" }
        ListElement{ timestamp: "2016-04"; expenses: "-3";  income: "2" }
        ListElement{ timestamp: "2016-05"; expenses: "-4";  income: "1" }
        ListElement{ timestamp: "2016-06"; expenses: "-2";  income: "2" }
        ListElement{ timestamp: "2016-07"; expenses: "-1";  income: "3" }
        ListElement{ timestamp: "2016-08"; expenses: "-5";  income: "1" }
        ListElement{ timestamp: "2016-09"; expenses: "-2";  income: "3" }
        ListElement{ timestamp: "2016-10"; expenses: "-5";  income: "2" }
        ListElement{ timestamp: "2016-11"; expenses: "-8";  income: "5" }
        ListElement{ timestamp: "2016-12"; expenses: "-3";  income: "3" }

        ListElement{ timestamp: "2017-01"; expenses: "-3";  income: "1" }
        ListElement{ timestamp: "2017-02"; expenses: "-4";  income: "2" }
        ListElement{ timestamp: "2017-03"; expenses: "-12"; income: "4" }
        ListElement{ timestamp: "2017-04"; expenses: "-13"; income: "6" }
        ListElement{ timestamp: "2017-05"; expenses: "-14"; income: "11" }
        ListElement{ timestamp: "2017-06"; expenses: "-7";  income: "7" }
        ListElement{ timestamp: "2017-07"; expenses: "-6";  income: "4" }
        ListElement{ timestamp: "2017-08"; expenses: "-4";  income: "15" }
        ListElement{ timestamp: "2017-09"; expenses: "-2";  income: "18" }
        ListElement{ timestamp: "2017-10"; expenses: "-29"; income: "25" }
        ListElement{ timestamp: "2017-11"; expenses: "-23"; income: "29" }
        ListElement{ timestamp: "2017-12"; expenses: "-5";  income: "9" }

        ListElement{ timestamp: "2018-01"; expenses: "-3";  income: "8" }
        ListElement{ timestamp: "2018-02"; expenses: "-8";  income: "14" }
        ListElement{ timestamp: "2018-03"; expenses: "-10"; income: "20" }
        ListElement{ timestamp: "2018-04"; expenses: "-12"; income: "24" }
        ListElement{ timestamp: "2018-05"; expenses: "-10"; income: "19" }
        ListElement{ timestamp: "2018-06"; expenses: "-5";  income: "8" }
        ListElement{ timestamp: "2018-07"; expenses: "-1";  income: "4" }
        ListElement{ timestamp: "2018-08"; expenses: "-7";  income: "12" }
        ListElement{ timestamp: "2018-09"; expenses: "-4";  income: "16" }
        ListElement{ timestamp: "2018-10"; expenses: "-22"; income: "33" }
        ListElement{ timestamp: "2018-11"; expenses: "-16"; income: "25" }
        ListElement{ timestamp: "2018-12"; expenses: "-2";  income: "7" }

        ListElement{ timestamp: "2019-01"; expenses: "-4";  income: "5"  }
        ListElement{ timestamp: "2019-02"; expenses: "-4";  income: "7"  }
        ListElement{ timestamp: "2019-03"; expenses: "-11"; income: "14"  }
        ListElement{ timestamp: "2019-04"; expenses: "-16"; income: "22"  }
        ListElement{ timestamp: "2019-05"; expenses: "-3";  income: "5"  }
        ListElement{ timestamp: "2019-06"; expenses: "-4";  income: "8"  }
        ListElement{ timestamp: "2019-07"; expenses: "-7";  income: "9"  }
        ListElement{ timestamp: "2019-08"; expenses: "-9";  income: "13"  }
        ListElement{ timestamp: "2019-09"; expenses: "-1";  income: "6"  }
        ListElement{ timestamp: "2019-10"; expenses: "-14"; income: "25"  }
        ListElement{ timestamp: "2019-11"; expenses: "-19"; income: "29"  }
        ListElement{ timestamp: "2019-12"; expenses: "-5";  income: "7"  }

        ListElement{ timestamp: "2020-01"; expenses: "-14"; income: "22"  }
        ListElement{ timestamp: "2020-02"; expenses: "-5";  income: "7"  }
        ListElement{ timestamp: "2020-03"; expenses: "-1";  income: "9"  }
        ListElement{ timestamp: "2020-04"; expenses: "-1";  income: "12"  }
        ListElement{ timestamp: "2020-05"; expenses: "-5";  income: "9"  }
        ListElement{ timestamp: "2020-06"; expenses: "-5";  income: "8"  }
        ListElement{ timestamp: "2020-07"; expenses: "-3";  income: "7"  }
        ListElement{ timestamp: "2020-08"; expenses: "-1";  income: "5"  }
        ListElement{ timestamp: "2020-09"; expenses: "-2";  income: "4"  }
        ListElement{ timestamp: "2020-10"; expenses: "-10"; income: "13"  }
        ListElement{ timestamp: "2020-11"; expenses: "-12"; income: "17"  }
        ListElement{ timestamp: "2020-12"; expenses: "-6";  income: "9"  }

        ListElement{ timestamp: "2021-01"; expenses: "-2";  income: "6"  }
        ListElement{ timestamp: "2021-02"; expenses: "-4";  income: "8"  }
        ListElement{ timestamp: "2021-03"; expenses: "-7";  income: "12"  }
        ListElement{ timestamp: "2021-04"; expenses: "-9";  income: "15"  }
        ListElement{ timestamp: "2021-05"; expenses: "-7";  income: "19"  }
        ListElement{ timestamp: "2021-06"; expenses: "-9";  income: "18"  }
        ListElement{ timestamp: "2021-07"; expenses: "-13"; income: "17"  }
        ListElement{ timestamp: "2021-08"; expenses: "-5";  income: "9"  }
        ListElement{ timestamp: "2021-09"; expenses: "-3";  income: "8"  }
        ListElement{ timestamp: "2021-10"; expenses: "-13"; income: "15"  }
        ListElement{ timestamp: "2021-11"; expenses: "-8";  income: "17"  }
        ListElement{ timestamp: "2021-12"; expenses: "-7";  income: "10"  }

        ListElement{ timestamp: "2022-01"; expenses: "-12";  income: "16"  }
        ListElement{ timestamp: "2022-02"; expenses: "-24";  income: "28"  }
        ListElement{ timestamp: "2022-03"; expenses: "-27";  income: "22"  }
        ListElement{ timestamp: "2022-04"; expenses: "-29";  income: "25"  }
        ListElement{ timestamp: "2022-05"; expenses: "-27";  income: "29"  }
        ListElement{ timestamp: "2022-06"; expenses: "-19";  income: "18"  }
        ListElement{ timestamp: "2022-07"; expenses: "-13";  income: "17"  }
        ListElement{ timestamp: "2022-08"; expenses: "-15";  income: "19"  }
        ListElement{ timestamp: "2022-09"; expenses: "-3";   income: "8"  }
        ListElement{ timestamp: "2022-10"; expenses: "-3";   income: "6"  }
        ListElement{ timestamp: "2022-11"; expenses: "-4";   income: "8"  }
        ListElement{ timestamp: "2022-12"; expenses: "-5";   income: "9"  }
    }
}

总结

本文介绍了QT数据可视化框架编程实战之三维柱状图可视化的运行效果以及具体实现代码。

如果读者对如何快速全面了解QT框架感兴趣,可以看一下这篇文章:

bird:快速全面了解QT软件界面开发技术

如果读者对如何学习QT框架有兴趣,可以看一下这篇文章:

bird:如何学习C/C++/QT软件开发技术

如果您认为这篇文章对您有所帮助,请您一定立即点赞+喜欢+收藏,本文作者将能从您的点赞+喜欢+收藏中获取到创作新的好文章的动力。如果您认为作者写的文章还有一些参考价值,您也可以关注这篇文章的作者。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值