mirror of https://github.com/qt/qtgraphs.git
widgetgraphgallery example: Use QRangeModel for the rainfall data
QRangeModel can be used conveniently read tables from range-based data. Replace the previously existing mappers by a QItemModelBarDataProxy based on QRangeModel. Pick-to: 6.10 Change-Id: Ic6b1ce66a41d8edf5ae080ea9974b44d45a22c4e Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
parent
32120c2030
commit
467bcff49d
|
@ -32,9 +32,6 @@ qt_add_executable(widgetgraphgallery
|
|||
|
||||
graphmodifier.cpp graphmodifier.h
|
||||
rainfalldata.cpp rainfalldata.h
|
||||
variantbardatamapping.cpp variantbardatamapping.h
|
||||
variantbardataproxy.cpp variantbardataproxy.h
|
||||
variantdataset.cpp variantdataset.h
|
||||
|
||||
scattergraph.cpp scattergraph.h
|
||||
scattergraphwidget.cpp scattergraphwidget.h
|
||||
|
|
|
@ -201,9 +201,9 @@ void BarGraph::initialize()
|
|||
auto *modeGroup = new QButtonGroup(m_container);
|
||||
auto *modeWeather = new QRadioButton(u"Temperature Data"_s, m_container);
|
||||
modeWeather->setChecked(true);
|
||||
auto *modeCustomProxy = new QRadioButton(u"Custom Proxy Data"_s, m_container);
|
||||
auto *modelProxy = new QRadioButton(u"Model Proxy Data"_s, m_container);
|
||||
modeGroup->addButton(modeWeather);
|
||||
modeGroup->addButton(modeCustomProxy);
|
||||
modeGroup->addButton(modelProxy);
|
||||
|
||||
//! [adding the slider]
|
||||
vLayout->addWidget(new QLabel(u"Rotate horizontally"_s));
|
||||
|
@ -238,7 +238,7 @@ void BarGraph::initialize()
|
|||
vLayout->addWidget(new QLabel(u"Axis label rotation"_s));
|
||||
vLayout->addWidget(axisLabelRotationSlider, 0, Qt::AlignTop);
|
||||
vLayout->addWidget(modeWeather, 0, Qt::AlignTop);
|
||||
vLayout->addWidget(modeCustomProxy, 1, Qt::AlignTop);
|
||||
vLayout->addWidget(modelProxy, 1, Qt::AlignTop);
|
||||
|
||||
// Raise the graph to the top of the widget stack, to hide UI if resized smaller
|
||||
m_quickWidget->raise();
|
||||
|
@ -365,10 +365,10 @@ void BarGraph::initialize()
|
|||
&QRadioButton::toggled,
|
||||
m_modifier,
|
||||
&GraphModifier::setDataModeToWeather);
|
||||
QObject::connect(modeCustomProxy,
|
||||
QObject::connect(modelProxy,
|
||||
&QRadioButton::toggled,
|
||||
m_modifier,
|
||||
&GraphModifier::setDataModeToCustom);
|
||||
&GraphModifier::setDataModeToModel);
|
||||
QObject::connect(modeWeather, &QRadioButton::toggled, seriesCheckBox, &QCheckBox::setEnabled);
|
||||
QObject::connect(modeWeather, &QRadioButton::toggled, rangeList, &QComboBox::setEnabled);
|
||||
QObject::connect(modeWeather,
|
||||
|
|
|
@ -201,98 +201,30 @@
|
|||
|
||||
\snippet 3d/widgetgraphgallery/graphmodifier.cpp center camera
|
||||
|
||||
\section2 Custom Proxy for Data
|
||||
\section2 Model Proxy for Data
|
||||
|
||||
When you toggle \uicontrol {Custom Proxy Data} data mode on, the graph in
|
||||
the example uses a custom dataset and the corresponding proxy.
|
||||
|
||||
Define a simple flexible data set, \c{VariantDataSet}, where each data item
|
||||
is a variant list. Each item can have multiple values, identified by their
|
||||
index in the list. In this case, the data set is designed to store monthly
|
||||
rainfall data. The value in index zero represents the year, the value in
|
||||
index one represents the month, and the value in index two represents the
|
||||
amount of rainfall in that month.
|
||||
|
||||
The custom proxy is similar to itemmodel-based proxies,
|
||||
QItemModelBarDataProxy, provided by QtGraphs, and it requires mapping to
|
||||
interpret the data.
|
||||
|
||||
\section3 Implement a data set
|
||||
|
||||
Define the data items as QVariantList objects. Add functionality for
|
||||
clearing the data set and querying a reference to the data contained in the
|
||||
set. Also, add signals to be emitted when data is added or the set is cleared:
|
||||
|
||||
\snippet 3d/widgetgraphgallery/variantdataset.h 0
|
||||
\dots 0
|
||||
\codeline
|
||||
\snippet 3d/widgetgraphgallery/variantdataset.h 1
|
||||
|
||||
\section3 Implement a data proxy
|
||||
|
||||
Derive the \c VariantBarDataProxy class from QBarDataProxy and implement a
|
||||
simple API of getters and setters for the data set and the mapping:
|
||||
|
||||
\snippet 3d/widgetgraphgallery/variantbardataproxy.h 0
|
||||
\dots 0
|
||||
\codeline
|
||||
\snippet 3d/widgetgraphgallery/variantbardataproxy.h 1
|
||||
|
||||
The proxy listens for changes in the data set and the mapping, resolving the
|
||||
data set if any changes are detected. While this implementation may not be
|
||||
particularly efficient, as any change triggers the re-resolving of the
|
||||
entire data set, it is not a concern for this example.
|
||||
|
||||
In the \c resolveDataSet() method, sort the variant data values into rows
|
||||
and columns based on the mapping. This is very similar to how the
|
||||
QItemModelBarDataProxy handles mapping, except you use list indexes instead
|
||||
of item model roles here. Once the values are sorted, generate a
|
||||
\c QBarDataArray out of them, and call the \c resetArray() method in the
|
||||
parent class:
|
||||
|
||||
\snippet 3d/widgetgraphgallery/variantbardataproxy.cpp 0
|
||||
|
||||
\section3 Implement a data mapper
|
||||
|
||||
Store the mapping information between \c VariantDataSet data item indexes
|
||||
and rows, columns, and values of \c QBarDataArray in
|
||||
\c VariantBarDataMapping. It contains the lists of rows and columns to be
|
||||
included in the resolved data:
|
||||
|
||||
\snippet 3d/widgetgraphgallery/variantbardatamapping.h 0
|
||||
\dots 0
|
||||
\codeline
|
||||
\snippet 3d/widgetgraphgallery/variantbardatamapping.h 1
|
||||
\dots 0
|
||||
\codeline
|
||||
\snippet 3d/widgetgraphgallery/variantbardatamapping.h 2
|
||||
\dots 0
|
||||
\codeline
|
||||
\snippet 3d/widgetgraphgallery/variantbardatamapping.h 3
|
||||
|
||||
The primary way to use a \c VariantBarDataMapping object is to give the
|
||||
mappings in the constructor, though you can also use the \c remap() method
|
||||
to set them later, either individually or all together. Emit a signal if
|
||||
mapping changes. The outcome is a simplified version of the mapping
|
||||
functionality of QItemModelBarDataProxy, adapted to work with variant lists
|
||||
instead of item models.
|
||||
When you toggle \uicontrol {Model Proxy Data} data mode on, the graph in
|
||||
the example uses an item model based dataset and the corresponding proxy.
|
||||
|
||||
\section3 RainfallData
|
||||
|
||||
Class \c RainfallData sets up a QItemModelBarDataProxy along with the series
|
||||
and axes.
|
||||
|
||||
\list 1
|
||||
\li Handle the setup of QBar3DSeries with the custom proxy in the \c RainfallData class:
|
||||
\li We use a \c{std::array<double, 12>} to store the values of a year
|
||||
indexed by month. The static \c readData() helper function reads
|
||||
the data, returning a QList of them indexed by year:
|
||||
|
||||
\snippet 3d/widgetgraphgallery/rainfalldata.cpp 1
|
||||
\dots
|
||||
|
||||
\li The QList represents a two dimensional array indexed by year and month,
|
||||
respectively. From this, we populate a QRangeModel and pass it to
|
||||
a QItemModelBarDataProxy() in the \c RainfallData class:
|
||||
|
||||
\snippet 3d/widgetgraphgallery/rainfalldata.cpp 0
|
||||
|
||||
\li Populate the variant data set in the \c addDataSet() method:
|
||||
|
||||
\snippet 3d/widgetgraphgallery/rainfalldata.cpp 1
|
||||
\dots
|
||||
|
||||
\li Use the custom proxy functions to add the data set to the series and set the mapping:
|
||||
|
||||
\snippet 3d/widgetgraphgallery/rainfalldata.cpp 2
|
||||
|
||||
\li Finally, add a function for getting the created series for displaying:
|
||||
|
||||
\snippet 3d/widgetgraphgallery/rainfalldata.h 0
|
||||
|
|
|
@ -377,7 +377,7 @@ void GraphModifier::setDataModeToWeather(bool enabled)
|
|||
changeDataMode(false);
|
||||
}
|
||||
|
||||
void GraphModifier::setDataModeToCustom(bool enabled)
|
||||
void GraphModifier::setDataModeToModel(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
changeDataMode(true);
|
||||
|
@ -432,11 +432,11 @@ void GraphModifier::setReverseValueAxis(int enabled)
|
|||
m_graph->valueAxis()->setReversed(enabled);
|
||||
}
|
||||
|
||||
void GraphModifier::changeDataMode(bool customData)
|
||||
void GraphModifier::changeDataMode(bool modelData)
|
||||
{
|
||||
int enabled = false;
|
||||
// Change between weather data and data from custom proxy
|
||||
if (customData) {
|
||||
// Change between weather data and data from model proxy
|
||||
if (modelData) {
|
||||
m_graph->removeSeries(m_primarySeries);
|
||||
m_graph->removeSeries(m_secondarySeries);
|
||||
m_graph->addSeries(m_customData->customSeries());
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
void setSmoothBars(int smooth);
|
||||
void setSeriesVisibility(int visible);
|
||||
void setReverseValueAxis(int enabled);
|
||||
void changeDataMode(bool customData);
|
||||
void changeDataMode(bool modelData);
|
||||
|
||||
public Q_SLOTS:
|
||||
void changeRange(int range);
|
||||
|
@ -46,7 +46,7 @@ public Q_SLOTS:
|
|||
void setAxisTitleFixed(bool enabled);
|
||||
void zoomToSelectedBar();
|
||||
void setDataModeToWeather(bool enabled);
|
||||
void setDataModeToCustom(bool enabled);
|
||||
void setDataModeToModel(bool enabled);
|
||||
|
||||
Q_SIGNALS:
|
||||
void shadowQualityChanged(int quality);
|
||||
|
|
|
@ -4,24 +4,88 @@
|
|||
|
||||
#include "rainfalldata.h"
|
||||
#include <QtCore/qfile.h>
|
||||
#include <QtCore/qrangemodel.h>
|
||||
#include <QtCore/qlist.h>
|
||||
#include <QtCore/qtextstream.h>
|
||||
#include <QtGraphs/q3dscene.h>
|
||||
#include <QtGraphs/qgraphstheme.h>
|
||||
#include <QtGraphs/qbar3dseries.h>
|
||||
#include <QtGraphs/qcategory3daxis.h>
|
||||
#include <QtGraphs/qgraphstheme.h>
|
||||
#include <QtGraphs/qitemmodelbardataproxy.h>
|
||||
#include <QtGraphs/qvalue3daxis.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
//! [1]
|
||||
using YearlyData = std::array<double, 12>;
|
||||
using ModelData = QList<YearlyData>;
|
||||
|
||||
static ModelData readData(const QString &fileName, int *firstYear)
|
||||
{
|
||||
ModelData result;
|
||||
|
||||
*firstYear = -1;
|
||||
|
||||
// Read data from a data file into the data item list
|
||||
QFile dataFile(fileName);
|
||||
if (!dataFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qWarning() << "Unable to open data file:" << dataFile.fileName() << dataFile.errorString();
|
||||
return result;
|
||||
}
|
||||
|
||||
QTextStream stream(&dataFile);
|
||||
int lastYear = -1;
|
||||
while (!stream.atEnd()) {
|
||||
QString line = stream.readLine();
|
||||
if (line.startsWith(u'#')) // Ignore comments
|
||||
continue;
|
||||
const auto strList = QStringView{line}.split(',', Qt::SkipEmptyParts);
|
||||
// Each line has three data items: Year, month, and rainfall value
|
||||
if (strList.size() < 3) {
|
||||
qWarning() << "Invalid row read from data:" << line;
|
||||
continue;
|
||||
}
|
||||
// Store year and month as int, and rainfall value as double
|
||||
bool yearOk{};
|
||||
bool monthOk{};
|
||||
bool valueOk{};
|
||||
const int year = strList.at(0).trimmed().toInt(&yearOk);
|
||||
const int month = strList.at(1).trimmed().toInt(&monthOk);
|
||||
const double value = strList.at(2).trimmed().toDouble(&valueOk);
|
||||
if (!yearOk || !monthOk || month < 1 || month > 12 || !valueOk) {
|
||||
qWarning() << "Invalid row values:" << line;
|
||||
continue;
|
||||
}
|
||||
if (year != lastYear) {
|
||||
if (lastYear == -1) {
|
||||
*firstYear = year;
|
||||
} else if (year != lastYear + 1) {
|
||||
qWarning() << "Non-consecutive years" << year << lastYear;
|
||||
return {};
|
||||
}
|
||||
lastYear = year;
|
||||
result.emplace_back(YearlyData{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
|
||||
}
|
||||
result.back()[month - 1] = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//! [1]
|
||||
|
||||
RainfallData::RainfallData()
|
||||
{
|
||||
// In data file the months are in numeric format, so create custom list
|
||||
for (int i = 1; i <= 12; ++i)
|
||||
m_numericMonths << QString::number(i);
|
||||
|
||||
updateYearsList(2010, 2022);
|
||||
|
||||
// Create proxy and series
|
||||
//! [0]
|
||||
m_proxy = new VariantBarDataProxy;
|
||||
int firstYear{};
|
||||
auto data = readData(":/data/raindata.txt"_L1, &firstYear);
|
||||
Q_ASSERT(!data.isEmpty());
|
||||
updateYearsList(firstYear, firstYear + int(data.size()) - 1);
|
||||
auto *model = new QRangeModel(data, this);
|
||||
|
||||
m_proxy = new QItemModelBarDataProxy(model);
|
||||
m_proxy->setUseModelCategories(true);
|
||||
m_series = new QBar3DSeries(m_proxy);
|
||||
//! [0]
|
||||
|
||||
|
@ -57,14 +121,9 @@ RainfallData::RainfallData()
|
|||
m_rowAxis->setTitleVisible(true);
|
||||
m_colAxis->setTitleVisible(true);
|
||||
m_valueAxis->setTitleVisible(true);
|
||||
|
||||
addDataSet();
|
||||
}
|
||||
|
||||
RainfallData::~RainfallData()
|
||||
{
|
||||
delete m_mapping;
|
||||
}
|
||||
RainfallData::~RainfallData() = default;
|
||||
|
||||
void RainfallData::updateYearsList(int start, int end)
|
||||
{
|
||||
|
@ -73,48 +132,3 @@ void RainfallData::updateYearsList(int start, int end)
|
|||
for (int i = start; i <= end; ++i)
|
||||
m_years << QString::number(i);
|
||||
}
|
||||
|
||||
//! [1]
|
||||
void RainfallData::addDataSet()
|
||||
{
|
||||
// Create a new variant data set and data item list
|
||||
m_dataSet = new VariantDataSet;
|
||||
auto *itemList = new VariantDataItemList;
|
||||
|
||||
// Read data from a data file into the data item list
|
||||
QFile dataFile(":/data/raindata.txt");
|
||||
if (dataFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QTextStream stream(&dataFile);
|
||||
while (!stream.atEnd()) {
|
||||
QString line = stream.readLine();
|
||||
if (line.startsWith('#')) // Ignore comments
|
||||
continue;
|
||||
const auto strList = QStringView{line}.split(',', Qt::SkipEmptyParts);
|
||||
// Each line has three data items: Year, month, and rainfall value
|
||||
if (strList.size() < 3) {
|
||||
qWarning() << "Invalid row read from data:" << line;
|
||||
continue;
|
||||
}
|
||||
// Store year and month as strings, and rainfall value as double
|
||||
// into a variant data item and add the item to the item list.
|
||||
auto *newItem = new VariantDataItem;
|
||||
for (int i = 0; i < 2; ++i)
|
||||
newItem->append(strList.at(i).trimmed().toString());
|
||||
newItem->append(strList.at(2).trimmed().toDouble());
|
||||
itemList->append(newItem);
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Unable to open data file:" << dataFile.fileName();
|
||||
}
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
// Add items to the data set and set it to the proxy
|
||||
m_dataSet->addItems(itemList);
|
||||
m_proxy->setDataSet(m_dataSet);
|
||||
|
||||
// Create new mapping for the data and set it to the proxy
|
||||
m_mapping = new VariantBarDataMapping(0, 1, 2, m_years, m_numericMonths);
|
||||
m_proxy->setMapping(m_mapping);
|
||||
//! [2]
|
||||
}
|
||||
|
|
|
@ -4,9 +4,14 @@
|
|||
#ifndef RAINFALLDATA_H
|
||||
#define RAINFALLDATA_H
|
||||
|
||||
#include "variantbardataproxy.h"
|
||||
#include <QtGraphs/qcategory3daxis.h>
|
||||
#include <QtGraphs/qvalue3daxis.h>
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qstringlist.h>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QBar3DSeries)
|
||||
QT_FORWARD_DECLARE_CLASS(QItemModelBarDataProxy)
|
||||
QT_FORWARD_DECLARE_CLASS(QBar3DSeries)
|
||||
QT_FORWARD_DECLARE_CLASS(QValue3DAxis)
|
||||
QT_FORWARD_DECLARE_CLASS(QCategory3DAxis)
|
||||
|
||||
class RainfallData : public QObject
|
||||
{
|
||||
|
@ -17,8 +22,6 @@ public:
|
|||
explicit RainfallData();
|
||||
~RainfallData() override;
|
||||
|
||||
void addDataSet();
|
||||
|
||||
//! [0]
|
||||
QBar3DSeries *customSeries() { return m_series; }
|
||||
//! [0]
|
||||
|
@ -29,11 +32,9 @@ public:
|
|||
|
||||
private:
|
||||
void updateYearsList(int start, int end);
|
||||
|
||||
QStringList m_years;
|
||||
QStringList m_numericMonths;
|
||||
VariantBarDataProxy *m_proxy;
|
||||
VariantBarDataMapping *m_mapping;
|
||||
VariantDataSet *m_dataSet;
|
||||
QItemModelBarDataProxy *m_proxy;
|
||||
QBar3DSeries *m_series;
|
||||
QValue3DAxis *m_valueAxis;
|
||||
QCategory3DAxis *m_rowAxis;
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "variantbardatamapping.h"
|
||||
|
||||
VariantBarDataMapping::VariantBarDataMapping(int rowIndex,
|
||||
int columnIndex,
|
||||
int valueIndex,
|
||||
const QStringList &rowCategories,
|
||||
const QStringList &columnCategories)
|
||||
: QObject(nullptr)
|
||||
{
|
||||
m_rowIndex = rowIndex;
|
||||
m_columnIndex = columnIndex;
|
||||
m_valueIndex = valueIndex;
|
||||
m_rowCategories = rowCategories;
|
||||
m_columnCategories = columnCategories;
|
||||
}
|
||||
|
||||
VariantBarDataMapping::~VariantBarDataMapping() = default;
|
||||
|
||||
void VariantBarDataMapping::setRowIndex(int index)
|
||||
{
|
||||
m_rowIndex = index;
|
||||
emit mappingChanged();
|
||||
}
|
||||
|
||||
int VariantBarDataMapping::rowIndex() const
|
||||
{
|
||||
return m_rowIndex;
|
||||
}
|
||||
|
||||
void VariantBarDataMapping::setColumnIndex(int index)
|
||||
{
|
||||
m_columnIndex = index;
|
||||
emit mappingChanged();
|
||||
}
|
||||
|
||||
int VariantBarDataMapping::columnIndex() const
|
||||
{
|
||||
return m_columnIndex;
|
||||
}
|
||||
|
||||
void VariantBarDataMapping::setValueIndex(int index)
|
||||
{
|
||||
m_valueIndex = index;
|
||||
emit mappingChanged();
|
||||
}
|
||||
|
||||
int VariantBarDataMapping::valueIndex() const
|
||||
{
|
||||
return m_valueIndex;
|
||||
}
|
||||
|
||||
void VariantBarDataMapping::setRowCategories(const QStringList &categories)
|
||||
{
|
||||
m_rowCategories = categories;
|
||||
emit mappingChanged();
|
||||
}
|
||||
|
||||
const QStringList &VariantBarDataMapping::rowCategories() const
|
||||
{
|
||||
return m_rowCategories;
|
||||
}
|
||||
|
||||
void VariantBarDataMapping::setColumnCategories(const QStringList &categories)
|
||||
{
|
||||
m_columnCategories = categories;
|
||||
emit mappingChanged();
|
||||
}
|
||||
|
||||
const QStringList &VariantBarDataMapping::columnCategories() const
|
||||
{
|
||||
return m_columnCategories;
|
||||
}
|
||||
|
||||
void VariantBarDataMapping::remap(int rowIndex,
|
||||
int columnIndex,
|
||||
int valueIndex,
|
||||
const QStringList &rowCategories,
|
||||
const QStringList &columnCategories)
|
||||
{
|
||||
m_rowIndex = rowIndex;
|
||||
m_columnIndex = columnIndex;
|
||||
m_valueIndex = valueIndex;
|
||||
m_rowCategories = rowCategories;
|
||||
m_columnCategories = columnCategories;
|
||||
emit mappingChanged();
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef VARIANTBARDATAMAPPING_H
|
||||
#define VARIANTBARDATAMAPPING_H
|
||||
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qstringlist.h>
|
||||
|
||||
class VariantBarDataMapping : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
//! [0]
|
||||
Q_PROPERTY(int rowIndex READ rowIndex WRITE setRowIndex NOTIFY rowIndexChanged)
|
||||
Q_PROPERTY(int columnIndex READ columnIndex WRITE setColumnIndex NOTIFY columnIndexChanged)
|
||||
Q_PROPERTY(int valueIndex READ valueIndex WRITE setValueIndex NOTIFY valueIndexChanged)
|
||||
Q_PROPERTY(QStringList rowCategories READ rowCategories WRITE setRowCategories NOTIFY
|
||||
rowCategoriesChanged)
|
||||
Q_PROPERTY(QStringList columnCategories READ columnCategories WRITE setColumnCategories NOTIFY
|
||||
columnCategoriesChanged)
|
||||
//! [0]
|
||||
public:
|
||||
//! [1]
|
||||
explicit VariantBarDataMapping(int rowIndex,
|
||||
int columnIndex,
|
||||
int valueIndex,
|
||||
const QStringList &rowCategories,
|
||||
const QStringList &columnCategories);
|
||||
//! [1]
|
||||
~VariantBarDataMapping() override;
|
||||
|
||||
void setRowIndex(int index);
|
||||
int rowIndex() const;
|
||||
void setColumnIndex(int index);
|
||||
int columnIndex() const;
|
||||
void setValueIndex(int index);
|
||||
int valueIndex() const;
|
||||
|
||||
void setRowCategories(const QStringList &categories);
|
||||
const QStringList &rowCategories() const;
|
||||
void setColumnCategories(const QStringList &categories);
|
||||
const QStringList &columnCategories() const;
|
||||
|
||||
//! [2]
|
||||
void remap(int rowIndex,
|
||||
int columnIndex,
|
||||
int valueIndex,
|
||||
const QStringList &rowCategories,
|
||||
const QStringList &columnCategories);
|
||||
//! [2]
|
||||
Q_SIGNALS:
|
||||
void rowIndexChanged();
|
||||
void columnIndexChanged();
|
||||
void valueIndexChanged();
|
||||
void rowCategoriesChanged();
|
||||
void columnCategoriesChanged();
|
||||
//! [3]
|
||||
void mappingChanged();
|
||||
//! [3]
|
||||
|
||||
private:
|
||||
// Indexes of the mapped items in the VariantDataItem
|
||||
int m_rowIndex = 0;
|
||||
int m_columnIndex = 1;
|
||||
int m_valueIndex = 2;
|
||||
|
||||
// For row/column items, sort items into these categories. Other categories
|
||||
// are ignored.
|
||||
QStringList m_rowCategories = {};
|
||||
QStringList m_columnCategories = {};
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,123 +0,0 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "variantbardataproxy.h"
|
||||
|
||||
VariantBarDataProxy::VariantBarDataProxy() = default;
|
||||
|
||||
VariantBarDataProxy::~VariantBarDataProxy()
|
||||
{
|
||||
delete m_dataSet;
|
||||
}
|
||||
|
||||
void VariantBarDataProxy::setDataSet(VariantDataSet *newSet)
|
||||
{
|
||||
if (!m_dataSet.isNull())
|
||||
QObject::disconnect(m_dataSet.data(), nullptr, this, nullptr);
|
||||
|
||||
m_dataSet = newSet;
|
||||
|
||||
if (!m_dataSet.isNull()) {
|
||||
QObject::connect(m_dataSet.data(),
|
||||
&VariantDataSet::itemsAdded,
|
||||
this,
|
||||
&VariantBarDataProxy::handleItemsAdded);
|
||||
QObject::connect(m_dataSet.data(),
|
||||
&VariantDataSet::dataCleared,
|
||||
this,
|
||||
&VariantBarDataProxy::handleDataCleared);
|
||||
}
|
||||
resolveDataSet();
|
||||
}
|
||||
|
||||
VariantDataSet *VariantBarDataProxy::dataSet()
|
||||
{
|
||||
return m_dataSet.data();
|
||||
}
|
||||
|
||||
void VariantBarDataProxy::setMapping(VariantBarDataMapping *mapping)
|
||||
{
|
||||
if (!m_mapping.isNull()) {
|
||||
QObject::disconnect(m_mapping.data(),
|
||||
&VariantBarDataMapping::mappingChanged,
|
||||
this,
|
||||
&VariantBarDataProxy::handleMappingChanged);
|
||||
}
|
||||
|
||||
m_mapping = mapping;
|
||||
|
||||
if (!m_mapping.isNull()) {
|
||||
QObject::connect(m_mapping.data(),
|
||||
&VariantBarDataMapping::mappingChanged,
|
||||
this,
|
||||
&VariantBarDataProxy::handleMappingChanged);
|
||||
}
|
||||
|
||||
resolveDataSet();
|
||||
}
|
||||
|
||||
VariantBarDataMapping *VariantBarDataProxy::mapping()
|
||||
{
|
||||
return m_mapping.data();
|
||||
}
|
||||
|
||||
void VariantBarDataProxy::handleItemsAdded(int index, int count)
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
Q_UNUSED(count);
|
||||
|
||||
// Resolve new items
|
||||
resolveDataSet();
|
||||
}
|
||||
|
||||
void VariantBarDataProxy::handleDataCleared()
|
||||
{
|
||||
// Data cleared, reset array
|
||||
resetArray();
|
||||
}
|
||||
|
||||
void VariantBarDataProxy::handleMappingChanged()
|
||||
{
|
||||
resolveDataSet();
|
||||
}
|
||||
|
||||
// Resolve entire dataset into QBarDataArray.
|
||||
//! [0]
|
||||
void VariantBarDataProxy::resolveDataSet()
|
||||
{
|
||||
// If we have no data or mapping, or the categories are not defined, simply
|
||||
// clear the array
|
||||
if (m_dataSet.isNull() || m_mapping.isNull() || !m_mapping->rowCategories().size()
|
||||
|| !m_mapping->columnCategories().size()) {
|
||||
resetArray();
|
||||
return;
|
||||
}
|
||||
const VariantDataItemList &itemList = m_dataSet->itemList();
|
||||
|
||||
int rowIndex = m_mapping->rowIndex();
|
||||
int columnIndex = m_mapping->columnIndex();
|
||||
int valueIndex = m_mapping->valueIndex();
|
||||
const QStringList &rowList = m_mapping->rowCategories();
|
||||
const QStringList &columnList = m_mapping->columnCategories();
|
||||
|
||||
// Sort values into rows and columns
|
||||
using ColumnValueMap = QHash<QString, float>;
|
||||
QHash<QString, ColumnValueMap> itemValueMap;
|
||||
for (const VariantDataItem *item : itemList) {
|
||||
itemValueMap[item->at(rowIndex).toString()][item->at(columnIndex).toString()]
|
||||
= item->at(valueIndex).toReal();
|
||||
}
|
||||
|
||||
// Create a new data array in format the parent class understands
|
||||
QBarDataArray newProxyArray;
|
||||
for (const QString &rowKey : rowList) {
|
||||
QBarDataRow newProxyRow(columnList.size());
|
||||
for (qsizetype i = 0; i < columnList.size(); ++i)
|
||||
newProxyRow[i].setValue(itemValueMap[rowKey][columnList.at(i)]);
|
||||
newProxyArray.append(newProxyRow);
|
||||
}
|
||||
|
||||
// Finally, reset the data array in the parent class
|
||||
resetArray(newProxyArray);
|
||||
}
|
||||
//! [0]
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef VARIANTBARDATAPROXY_H
|
||||
#define VARIANTBARDATAPROXY_H
|
||||
|
||||
#include <QtCore/qpointer.h>
|
||||
#include <QtGraphs/qbardataproxy.h>
|
||||
#include "variantbardatamapping.h"
|
||||
#include "variantdataset.h"
|
||||
|
||||
//! [0]
|
||||
class VariantBarDataProxy : public QBarDataProxy
|
||||
//! [0]
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit VariantBarDataProxy();
|
||||
~VariantBarDataProxy() override;
|
||||
|
||||
//! [1]
|
||||
// Doesn't gain ownership of the dataset, but does connect to it to listen for
|
||||
// data changes.
|
||||
void setDataSet(VariantDataSet *newSet);
|
||||
VariantDataSet *dataSet();
|
||||
|
||||
// Map key (row, column, value) to value index in data item (VariantItem).
|
||||
// Doesn't gain ownership of mapping, but does connect to it to listen for
|
||||
// mapping changes. Modifying mapping that is set to proxy will trigger
|
||||
// dataset re-resolving.
|
||||
void setMapping(VariantBarDataMapping *mapping);
|
||||
VariantBarDataMapping *mapping();
|
||||
//! [1]
|
||||
|
||||
public Q_SLOTS:
|
||||
void handleItemsAdded(int index, int count);
|
||||
void handleDataCleared();
|
||||
void handleMappingChanged();
|
||||
|
||||
private:
|
||||
void resolveDataSet();
|
||||
|
||||
QPointer<VariantDataSet> m_dataSet;
|
||||
QPointer<VariantBarDataMapping> m_mapping;
|
||||
|
||||
Q_DISABLE_COPY(VariantBarDataProxy)
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "variantdataset.h"
|
||||
|
||||
VariantDataSet::VariantDataSet() = default;
|
||||
|
||||
VariantDataSet::~VariantDataSet()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void VariantDataSet::clear()
|
||||
{
|
||||
for (VariantDataItem *item : m_variantData) {
|
||||
item->clear();
|
||||
delete item;
|
||||
}
|
||||
m_variantData.clear();
|
||||
emit dataCleared();
|
||||
}
|
||||
|
||||
int VariantDataSet::addItem(VariantDataItem *item)
|
||||
{
|
||||
m_variantData.append(item);
|
||||
int addIndex = m_variantData.size();
|
||||
|
||||
emit itemsAdded(addIndex, 1);
|
||||
return addIndex;
|
||||
}
|
||||
|
||||
int VariantDataSet::addItems(VariantDataItemList *itemList)
|
||||
{
|
||||
int newCount = itemList->size();
|
||||
int addIndex = m_variantData.size();
|
||||
m_variantData.append(*itemList);
|
||||
delete itemList;
|
||||
emit itemsAdded(addIndex, newCount);
|
||||
return addIndex;
|
||||
}
|
||||
|
||||
const VariantDataItemList &VariantDataSet::itemList() const
|
||||
{
|
||||
return m_variantData;
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef VARIANTDATASET_H
|
||||
#define VARIANTDATASET_H
|
||||
|
||||
#include <QtCore/qvariantlist.h>
|
||||
|
||||
//! [0]
|
||||
using VariantDataItem = QVariantList;
|
||||
using VariantDataItemList = QList<VariantDataItem *>;
|
||||
//! [0]
|
||||
|
||||
class VariantDataSet : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit VariantDataSet();
|
||||
~VariantDataSet();
|
||||
|
||||
//! [1]
|
||||
void clear();
|
||||
|
||||
int addItem(VariantDataItem *item);
|
||||
int addItems(VariantDataItemList *itemList);
|
||||
|
||||
const VariantDataItemList &itemList() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void itemsAdded(int index, int count);
|
||||
void dataCleared();
|
||||
//! [1]
|
||||
|
||||
private:
|
||||
VariantDataItemList m_variantData;
|
||||
|
||||
Q_DISABLE_COPY(VariantDataSet)
|
||||
};
|
||||
|
||||
#endif
|
|
@ -15,9 +15,6 @@ SOURCES += main.cpp \
|
|||
bargraph.cpp \
|
||||
graphmodifier.cpp \
|
||||
rainfalldata.cpp \
|
||||
variantdataset.cpp \
|
||||
variantbardataproxy.cpp \
|
||||
variantbardatamapping.cpp \
|
||||
scattergraph.cpp \
|
||||
scatterdatamodifier.cpp \
|
||||
surfacegraph.cpp \
|
||||
|
@ -31,9 +28,6 @@ HEADERS += \
|
|||
bargraph.h \
|
||||
graphmodifier.h \
|
||||
rainfalldata.h \
|
||||
variantdataset.h \
|
||||
variantbardataproxy.h \
|
||||
variantbardatamapping.h \
|
||||
scattergraph.h \
|
||||
scatterdatamodifier.h \
|
||||
surfacegraph.h \
|
||||
|
|
Loading…
Reference in New Issue