Qt 5.9 | Qt Data Visualization | Qt Quick 2 Bars Example | main.qml Example File

Qt 5.9.9 Reference Documentation

# main.qml Example File

qmlbars/qml/qmlbars/main.qml

      /****************************************************************************
      **
      ** Copyright (C) 2016 The Qt Company Ltd.
      ** Contact: https://www.qt.io/licensing/
      **
      ** This file is part of the Qt Data Visualization module of the Qt Toolkit.
      **
      ** $QT_BEGIN_LICENSE:GPL$
      ** Commercial License Usage
      ** Licensees holding valid commercial Qt licenses may use this file in
      ** accordance with the commercial license agreement provided with the
      ** Software or, alternatively, in accordance with the terms contained in
      ** a written agreement between you and The Qt Company. For licensing terms
      ** and conditions see https://www.qt.io/terms-conditions. For further
      ** information use the contact form at https://www.qt.io/contact-us.
      **
      ** GNU General Public License Usage
      ** Alternatively, this file may be used under the terms of the GNU
      ** General Public License version 3 or (at your option) any later version
      ** approved by the KDE Free Qt Foundation. The licenses are as published by
      ** the Free Software Foundation and appearing in the file LICENSE.GPL3
      ** included in the packaging of this file. Please review the following
      ** information to ensure the GNU General Public License requirements will
      ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
      **
      ** $QT_END_LICENSE$
      **
      ****************************************************************************/

      import QtQuick 2.1
      import QtQuick.Controls 1.0
      import QtQuick.Layouts 1.0
      import QtDataVisualization 1.1
      import QtQuick.Window 2.0
      import "."

      Rectangle {
          id: mainview
          width: 1280
          height: 1024

          property int buttonLayoutHeight: 180;
          state: Screen.width < Screen.height ? "portrait" : "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
              var currentRow = tableView.currentRow
              if (currentRow === -1 || checkTimestamp !== graphData.model.get(currentRow).timestamp) {
                  var totalRows = tableView.rowCount;
                  for (var i = 0; i < totalRows; i++) {
                      var modelTimestamp = graphData.model.get(i).timestamp
                      if (modelTimestamp === checkTimestamp) {
                          tableView.currentRow = i
                          // Workaround to 5.2 row selection issue
                          if (typeof tableView.selection != "undefined") {
                              tableView.selection.clear()
                              tableView.selection.select(i)
                          }
                          break
                      }
                  }
              }
          }

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

              Bars3D {
                  id: barGraph
                  width: dataView.width
                  height: dataView.height
                  shadowQuality: AbstractGraph3D.ShadowQualityMedium
                  selectionMode: AbstractGraph3D.SelectionItem
                  theme: Theme3D {
                      type: Theme3D.ThemeRetro
                      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: 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.MMBCumulative
                      }

                      ColorGradient {
                          id: secondaryGradient
                          ColorGradientStop { position: 1.0; color: "#FF0000" }
                          ColorGradientStop { position: 0.0; color: "#600000" }
                      }

                      onSelectedBarChanged: handleSelectionChange(secondarySeries, position)
                  }

                  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
                      }

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

                      onSelectedBarChanged: handleSelectionChange(barSeries, position)
                  }
              }
          }

          TableView {
              id: tableView
              anchors.top: parent.top
              anchors.left: parent.left
              TableViewColumn{ role: "timestamp" ; title: "Month" ; width: tableView.width / 2 }
              TableViewColumn{ role: "expenses" ; title: "Expenses" ; width: tableView.width / 4 }
              TableViewColumn{ role: "income" ; title: "Income" ; width: tableView.width / 4 }
              itemDelegate: Item {
                  Text {
                      id: delegateText
                      anchors.verticalCenter: parent.verticalCenter
                      width: parent.width
                      anchors.leftMargin: 4
                      anchors.left: parent.left
                      anchors.right: parent.right
                      color: styleData.textColor
                      elide: styleData.elideMode
                      text: customText
                      horizontalAlignment: styleData.textAlignment

                      property string originalText: styleData.value
                      property string customText

                      onOriginalTextChanged: {
                          if (styleData.column === 0) {
                              if (delegateText.originalText !== "") {
                                  var pattern = /(\d\d\d\d)-(\d\d)/
                                  var matches = pattern.exec(delegateText.originalText)
                                  var colIndex = parseInt(matches[2], 10) - 1
                                  delegateText.customText = matches[1] + " - " + graphAxes.column.labels[colIndex]
                              }
                          } else {
                              delegateText.customText = originalText
                          }
                      }
                  }
              }

              model: graphData.model

              onCurrentRowChanged: {
                  var timestamp = graphData.model.get(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)
              }
          }

          ColumnLayout {
              id: controlLayout
              spacing: 0

              Button {
                  id: changeDataButton
                  Layout.fillWidth: true
                  Layout.fillHeight: true
                  text: "Show 2010 - 2012"
                  clip: true
                  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 2010 - 2012"
                      } else { // text === "Show 2010 - 2012"
                          // 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 = ["2010", "2011", "2012"]
                          secondaryProxy.rowCategories = ["2010", "2011", "2012"]
                          text = "Show yearly totals"
                      }
                  }
              }

              Button {
                  id: shadowToggle
                  Layout.fillWidth: true
                  Layout.fillHeight: true
                  text: barGraph.shadowsSupported ? "Hide Shadows" : "Shadows not supported"
                  clip: true
                  enabled: barGraph.shadowsSupported
                  onClicked: {
                      if (barGraph.shadowQuality == AbstractGraph3D.ShadowQualityNone) {
                          barGraph.shadowQuality = AbstractGraph3D.ShadowQualityMedium;
                          text = "Hide Shadows"
                      } else {
                          barGraph.shadowQuality = AbstractGraph3D.ShadowQualityNone;
                          text = "Show Shadows"
                      }
                  }
              }

              Button {
                  id: seriesToggle
                  Layout.fillWidth: true
                  Layout.fillHeight: true
                  text: "Show Expenses"
                  clip: true
                  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"
                      }
                  }
              }
          }

          states: [
              State  {
                  name: "landscape"
                  PropertyChanges {
                      target: dataView
                      width: mainview.width / 4 * 3
                      height: mainview.height
                  }
                  PropertyChanges  {
                      target: tableView
                      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: tableView.bottom
                      anchors.bottom: mainview.bottom
                      anchors.left: mainview.left
                      anchors.right: dataView.left
                  }
              },
              State  {
                  name: "portrait"
                  PropertyChanges {
                      target: dataView
                      width: mainview.height / 4 * 3
                      height: mainview.width
                  }
                  PropertyChanges  {
                      target: tableView
                      height: mainview.width
                      anchors.right: controlLayout.left
                      anchors.left: mainview.left
                      anchors.bottom: dataView.top
                  }
                  PropertyChanges  {
                      target: controlLayout
                      width: mainview.height / 4
                      height: mainview.width / 4
                      anchors.top: mainview.top
                      anchors.bottom: dataView.top
                      anchors.left: undefined
                      anchors.right: mainview.right
                  }
              }
          ]
      }