简单条形图
在 QML 应用程序中使用Bars3D 。
Simple Bar Graph演示如何使用Bars3D 和 QML 制作简单的 3D 柱形图。
以下各节将介绍如何切换系列和同时显示多个系列。有关 QML 应用程序基本功能的更多信息,请参阅Simple Scatter Graph(简单散点图)。
运行示例
要从 Qt Creator,打开Welcome 模式,并从Examples 选择示例。更多信息,请参阅Qt Creator: 教程:构建并运行。
数据
示例数据集是一家虚构公司几年来的月收入和支出。数据定义在Data.qml
的列表模型中,如下所示:
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" } ...
每个数据项有三个角色:时间戳、收入和支出。时间戳值的格式为:<four digit year>-<two digit month>
。通常,您会将年和月映射到条形图的行和列中,但您只能将收入或支出显示为值。
现在,将数据添加到Bars3D 图表中。在其中创建两个Bar3DSeries ,首先是收入系列:
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.MultiMatchBehavior.Cumulative } ...
数据附加到系列内ItemModelBarDataProxy 的itemModel
属性。对于valueRole
,指定income
字段,因为它包含所需的值。由于年和月都在同一个字段中,因此提取年和月的过程比较复杂。要提取这些值,请为rowRole
和columnRole
指定timestamp
字段。此外,还要为这些角色指定搜索模式和替换规则,以便为每个角色提取字段内容的正确部分。搜索模式是一个普通的 JavaScript 正则表达式,替换规则指定了与正则表达式匹配的字段内容的替换内容。在本例中,只用年或月替换整个字段内容,年或月是行和列的第一个捕获子串。有关使用正则表达式替换功能的更多信息,请参阅QString::replace(const QRegExp &rx, constQString &after) 函数文档。
multiMatchBehavior
属性指定了多个项目模型项目匹配相同行/列组合时的处理方法。在这种情况下,将它们的值相加。在显示每个月份的值时,该属性没有任何作用,因为我们的项目模型中没有重复的月份。不过,在以后要显示年度总计时,这个属性就变得很重要了。
然后,为支出添加另一个系列:
Bar3DSeries { id: secondarySeries visible: false itemLabelFormat: "Expenses, @colLabel, @rowLabel: -@valueLabel" baseGradient: secondaryGradient ItemModelBarDataProxy { id: secondaryProxy itemModel: graphData.model rowRole: "timestamp" columnRole: "timestamp" valueRole: "expenses" rowRolePattern: /^(\d\d\d\d).*$/ columnRolePattern: /^.*-(\d\d)$/ valueRolePattern: /-/ rowRoleReplace: "\\1" columnRoleReplace: "\\1" multiMatchBehavior: ItemModelBarDataProxy.MultiMatchBehavior.Cumulative } ...
模型中的支出为负值,但可以显示为正条形图,以便于与收入条形图进行比较。使用valueRolePattern
删除负号,无需指定替换字符串,因为默认替换为空字符串。
使用visible
系列属性暂时隐藏第二个系列。
自定义坐标轴标签
Axes.qml
重新定义了列轴的类别标签,因为数据中包含月份数字,这会使标签变得杂乱无章:
Category3DAxis { id: columnAxis labels: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] labelAutoAngle: 30 }
为使坐标轴标签在摄像机角度较低时更易读,可设置坐标轴标签自动旋转。
切换系列
在main.qml
中,设置图表和各种用户界面元素。这里有三个有趣的代码块值得强调。第一个代码块展示了如何通过简单改变两个系列的可见性,在收入、支出和两者之间切换可视化数据:
onClicked: { if (text === "Show Expenses") { barSeries.visible = false secondarySeries.visible = true barGraph.valueAxis.labelFormat = "-%.2f M\u20AC" secondarySeries.itemLabelFormat = "Expenses, @colLabel, @rowLabel: @valueLabel" text = "Show Both" } else if (text === "Show Both") { barSeries.visible = true barGraph.valueAxis.labelFormat = "%.2f M\u20AC" secondarySeries.itemLabelFormat = "Expenses, @colLabel, @rowLabel: -@valueLabel" text = "Show Income" } else { // text === "Show Income" secondarySeries.visible = false text = "Show Expenses" } }
对坐标轴标签格式和项目选择标签格式进行了调整,以正确显示支出的负号,而支出实际上被解析为正值。
第二个有趣的部分是通过调整代理属性来改变可视化数据:
onClicked: { if (text === "Show yearly totals") { modelProxy.autoRowCategories = true secondaryProxy.autoRowCategories = true modelProxy.columnRolePattern = /^.*$/ secondaryProxy.columnRolePattern = /^.*$/ graphAxes.value.autoAdjustRange = true barGraph.columnAxis = graphAxes.total text = "Show all years" } else if (text === "Show all years") { modelProxy.autoRowCategories = true secondaryProxy.autoRowCategories = true modelProxy.columnRolePattern = /^.*-(\d\d)$/ secondaryProxy.columnRolePattern = /^.*-(\d\d)$/ graphAxes.value.min = 0 graphAxes.value.max = 35 barGraph.columnAxis = graphAxes.column text = "Show 2020 - 2022" } else { // text === "Show 2020 - 2022" // Explicitly defining row categories, since we do not want to show data for // all years in the model, just for the selected ones. modelProxy.autoRowCategories = false secondaryProxy.autoRowCategories = false modelProxy.rowCategories = ["2020", "2021", "2022"] secondaryProxy.rowCategories = ["2020", "2021", "2022"] text = "Show yearly totals" } }
要显示年度总数,可将每年的 12 个月合并为一个条形图。这可以通过指定一个与所有模型项匹配的columnRolePattern
来实现。这样,数列将只有一列。之前为代理指定的累计multiMatchBehavior
现在变得相关了,每年所有 12 个月的值都会累加到一个柱形图中。
要只显示年份子集,可将ItemModelBarDataProxy 项上的autoRowCategories
设置为 false,并明确定义行类别。这样,只有指定行类别中的项目才会可视化。
第三个有趣的代码块展示了如何通过ItemModelBarDataProxy 方法rowCategoryIndex()
和columnCategoryIndex()
获取项目的行和列索引(如果知道行和列的值的话):
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)
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.