简单柱状图
在 QML 应用中使用 Bars3D。
简单柱状图 展示如何使用 Bars3D 和 QML 制作简单 3D 柱状图。
以下章节描述了如何切换序列以及一次显示多个序列的方式。有关基本 QML 应用功能的信息,请参阅 简单散点图。
运行示例
要从 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" } ...
每个数据项有三个角色:时间戳、收入和支出。时间戳值格式为:<四位数年份>-<两位数月份>
。通常,您会将年份和月份映射到柱状图的行和列中,但您只能显示收入或支出作为值。
现在,将数据添加到 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, const QString &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
重新定义了列轴的类别标签,因为数据包含月份的数字,这会使标签杂乱不堪。
CategoryAxis3D { id: columnAxis labels: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] labelAutoRotation: 30 }
为了使轴标签在低相机角度下更具可读性,请设置自动轴标签旋转。
切换系列
在 main.qml
中设置图和各种UI元素。这里有三个值得注意的代码块。第一个代码块展示了如何通过简单地更改两个系列的可视性来在收入、支出和两者之间切换可视化的数据
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"; } }
为了显示年度总计,将每年十二个月合并为一个条形图。这是通过指定一个 columnRolePattern
来实现的,它可以匹配所有模型项。这样,数据代理将只有一个列。早期为代理指定的累积 multiMatchBehavior
现在变得相关, causing the values of all twelve months of each year to be added up into a single bar.
要仅显示年份的子集,请在 ItemModelBarDataProxy 元素上将 autoRowCategories
设置为 false,并显式定义行类别。这样,只有指定的行类别中的项目将被可视化。
第三个有趣的代码块展示了如何使用 ItemModelBarDataProxy 方法 rowCategoryIndex()
和 columnCategoryIndex()
来获取已知行和列值的项目的行和列索引。
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); }
© 2024 Qt 公司有限。此处包含的文档贡献是各自所有者的版权。本提供的文档是根据自由软件基金会发布的 GNU 自由文档许可证版本 1.3 的条款授予的。Qt 及相关商标是芬兰和/或其他国家 Qt 公司的商标。所有其他商标均为各自所有者的财产。