Einfaches Balkendiagramm

Verwendung von Bars3D in einer QML-Anwendung.

Simple Bar Graph zeigt, wie man mit Bars3D und QML ein einfaches 3D-Balkendiagramm erstellt.

In den folgenden Abschnitten wird beschrieben, wie Sie Serien umschalten und mehr als eine Serie gleichzeitig anzeigen können. Weitere Informationen zur grundlegenden Funktionalität von QML-Anwendungen finden Sie unter Einfaches Streudiagramm.

Ausführen des Beispiels

Zum Ausführen des Beispiels von Qt Creatorzu starten, öffnen Sie den Modus Welcome und wählen Sie das Beispiel unter Examples aus. Weitere Informationen finden Sie unter Erstellen und Ausführen eines Beispiels.

Daten

Der Beispieldatensatz besteht aus den monatlichen Einnahmen und Ausgaben eines fiktiven Unternehmens über mehrere Jahre. Die Daten sind in einem Listenmodell in Data.qml wie folgt definiert:

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" }
    ...

Jedes Datenelement hat drei Rollen: Zeitstempel, Einnahmen und Ausgaben. Der Zeitstempelwert hat das Format: <four digit year>-<two digit month>. Normalerweise würden Sie Jahre und Monate den Zeilen und Spalten eines Balkendiagramms zuordnen, aber Sie können nur entweder Einnahmen oder Ausgaben als Wert anzeigen.

Fügen Sie nun die Daten in das Diagramm Bars3D ein. Erstellen Sie darin zwei Bar3DSeries, beginnend mit einer Reihe für die Einnahmen:

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
    }
    ...

Die Daten werden an die Eigenschaft itemModel der ItemModelBarDataProxy innerhalb der Reihe angehängt. Für valueRole geben Sie das Feld income an, da es den gewünschten Wert enthält. Die Ermittlung der Jahre und Monate ist etwas komplizierter, da sie sich beide im selben Feld befinden. Um diese Werte zu extrahieren, geben Sie das Feld timestamp sowohl für rowRole als auch für columnRole an, und geben Sie zusätzlich ein Suchmuster und eine Ersetzungsregel für diese Rollen an, um den richtigen Teil des Feldinhalts für jede Rolle zu extrahieren. Das Suchmuster ist ein normaler regulärer JavaScript-Ausdruck und die Ersetzungsregel gibt an, wodurch der Feldinhalt, der mit dem regulären Ausdruck übereinstimmt, ersetzt wird. In diesem Fall wird der gesamte Feldinhalt nur durch das Jahr oder den Monat ersetzt, der die erste erfasste Teilzeichenkette für beide Zeilen und Spalten ist. Weitere Informationen über die Ersetzungsfunktion mit regulären Ausdrücken finden Sie in der Dokumentation der Funktion QString::replace(const QRegExp &rx, const QString &after).

Die Eigenschaft multiMatchBehavior gibt an, was zu tun ist, wenn mehrere Elementmodellelemente auf dieselbe Zeilen-/Spaltenkombination passen. In diesem Fall werden ihre Werte addiert. Diese Eigenschaft hat keine Auswirkungen, wenn die Werte für jeden Monat angezeigt werden, da es in unserem Artikelmodell keine doppelten Monate gibt, aber sie wird später relevant, wenn Sie die Jahressummen anzeigen möchten.

Fügen Sie dann eine weitere Reihe für die Ausgaben hinzu:

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
    }
    ...

Das Modell enthält Ausgaben als negative Werte, aber Sie möchten sie als positive Balken darstellen, damit sie leicht mit den Einnahmen verglichen werden können. Verwenden Sie valueRolePattern, um das Minuszeichen zu entfernen, um dies zu erreichen. Es muss keine Ersetzungszeichenfolge angegeben werden, da die Standard-Ersetzung eine leere Zeichenfolge ist.

Verwenden Sie die Eigenschaft visible der Reihe, um die zweite Reihe vorerst auszublenden.

Benutzerdefinierte Achsenbeschriftungen

Axes.qml definiert die Kategoriebeschriftungen für die Spaltenachse neu, da die Daten Zahlen für Monate enthalten, die die Beschriftungen überladen würden:

CategoryAxis3D {
    id: columnAxis
    labels: ["January", "February", "March", "April", "May", "June",
        "July", "August", "September", "October", "November", "December"]
    labelAutoRotation: 30
}

Um die Achsenbeschriftungen bei niedrigen Kamerawinkeln besser lesbar zu machen, stellen Sie die automatische Drehung der Achsenbeschriftung ein.

Umschalten von Serien

Richten Sie unter main.qml das Diagramm und verschiedene UI-Elemente ein. Es gibt drei interessante Codeblöcke, die hier hervorzuheben sind. Der erste zeigt, wie man die visualisierten Daten zwischen Einnahmen, Ausgaben und beidem ändern kann, indem man einfach die Sichtbarkeit der beiden Reihen ändert:

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";
    }
}

Das Achsenbeschriftungsformat und die Formate der Elementauswahl werden so angepasst, dass das negative Vorzeichen für Ausgaben, die eigentlich als positive Werte aufgelöst wurden, richtig angezeigt wird.

Im zweiten interessanten Block werden die visualisierten Daten durch Anpassung der Proxy-Eigenschaften geändert:

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";
    }
}

Um die Jahressummen anzuzeigen, werden die zwölf Monate eines jeden Jahres zu einem einzigen Balken zusammengefasst. Dies wird erreicht, indem ein columnRolePattern angegeben wird, das mit allen Modellelementen übereinstimmt. Auf diese Weise wird der Daten-Proxy nur eine einzige Spalte haben. Die zuvor für den Proxy angegebene kumulative multiMatchBehavior wird jetzt relevant, da die Werte aller zwölf Monate jedes Jahres zu einem einzigen Balken addiert werden.

Wenn Sie nur eine Teilmenge der Jahre anzeigen möchten, setzen Sie autoRowCategories im Element ItemModelBarDataProxy auf false und definieren Sie die Zeilenkategorien explizit. Auf diese Weise werden nur die Elemente in den angegebenen Zeilenkategorien angezeigt.

Der dritte interessante Block zeigt, wie man den Zeilen- und Spaltenindex eines Elements erhält, wenn man die Zeilen- und Spaltenwerte kennt, indem man die Methoden ItemModelBarDataProxy rowCategoryIndex() und columnCategoryIndex() verwendet:

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);
}

Beispielprojekt @ code.qt.io

© 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.