declarativeboxplotseries.cpp
476 lines
| 15.9 KiB
| text/x-c
|
CppLexer
|
r0 | /**************************************************************************** | ||
** | ||||
** Copyright (C) 2016 The Qt Company Ltd. | ||||
** Contact: https://www.qt.io/licensing/ | ||||
** | ||||
** This file is part of the Qt Charts 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$ | ||||
** | ||||
****************************************************************************/ | ||||
#include "declarativebarseries.h" | ||||
#include "declarativeboxplotseries.h" | ||||
#include <QtCharts/QBoxSet> | ||||
#include <QtCharts/QVBoxPlotModelMapper> | ||||
QT_CHARTS_BEGIN_NAMESPACE | ||||
/*! | ||||
\qmltype BoxSet | ||||
\instantiates QBoxSet | ||||
\inqmlmodule QtCharts | ||||
\brief Building block for box-and-whiskers chart. | ||||
BoxSet represents one box-and-whiskers item. It takes five values to create a graphical | ||||
representation of range and three medians. There are two ways to give the values. The first one | ||||
is with constructor or with append method. In these the values have to be given in the following | ||||
order: lower extreme, lower quartile, median, upper quartile and upper extreme. The second | ||||
method is to create an empty QBoxSet instance and give the values using value specific methods. | ||||
\sa BoxPlotSeries | ||||
*/ | ||||
/*! | ||||
\qmlproperty string BoxSet::values | ||||
The values on the box-and-whiskers set. | ||||
*/ | ||||
/*! | ||||
\qmlproperty string BoxSet::label | ||||
Defines the label of the category of the box-and-whiskers set. | ||||
*/ | ||||
/*! | ||||
\qmlproperty int BoxSet::count | ||||
The count of values on the box-and-whiskers set | ||||
*/ | ||||
/*! | ||||
\qmlmethod void BoxSet::at(int index) | ||||
Returns the value at \a index position. | ||||
*/ | ||||
/*! | ||||
\qmlmethod void BoxSet::append(qreal value) | ||||
Appends new value \a value to the end of set. | ||||
*/ | ||||
/*! | ||||
\qmlmethod void BoxSet::clear() | ||||
Sets all values on the set to 0. | ||||
*/ | ||||
/*! | ||||
\qmlmethod void BoxSet::setValue(int index, qreal value) | ||||
Sets a new \a value on the \a index position. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxSet::onClicked() | ||||
This signal is emitted when the user clicks with a mouse on top of box-and-whiskers item. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxSet::onPressed() | ||||
This signal is emitted when the user presses with a mouse on top of box-and-whiskers item. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxSet::onReleased() | ||||
This signal is emitted when the user releases with a mouse on top of box-and-whiskers item. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxSet::onDoubleClicked() | ||||
This signal is emitted when the user doubleclicks with a mouse on top of box-and-whiskers item. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxSet::onHovered(bool status) | ||||
The signal is emitted if mouse is hovered on top of box-and-whiskers item. | ||||
Parameter \a status is true, if mouse entered on top of the item, and false if mouse left from top of the item. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxSet::onPenChanged() | ||||
This signal is emitted when the pen of the box-and-whiskers item has changed. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxSet::onBrushChanged() | ||||
This signal is emitted when the brush of the box-and-whiskers item has changed. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxSet::onChangedValues() | ||||
This signal is emitted when multiple values have been changed on the box-and-whiskers item. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxSet::onChangedValue(int index) | ||||
This signal is emitted values the value in the box-and-whiskers item has been modified. | ||||
Parameter \a index indicates the position of the modified value. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxSet::onCleared() | ||||
This signal is emitted when all the values on the set are cleared to 0. | ||||
*/ | ||||
/*! | ||||
\qmltype BoxPlotSeries | ||||
\instantiates QBoxPlotSeries | ||||
\inqmlmodule QtCharts | ||||
\inherits AbstractSeries | ||||
\brief Series for creating box-and-whiskers chart. | ||||
BoxPlotSeries represents a series of data shown as box-and-whiskers bars. The purpose of this | ||||
class is to act as a container for single box-and-whiskers items. Each item is drawn to own | ||||
slot. If chart includes multiple instances of BoxPlotSeries then box-and-whiskers items with the | ||||
same index are drawn to same slot. | ||||
\note The slot, each item in BoxPlotSeries is drawn, represents a category in BarCategoryAxis. | ||||
The category labels have to be unique. If same category label is defined for several | ||||
box-and-whisker items only the first one is drawn. | ||||
The following QML shows how to create a simple box-and-whiskers chart: | ||||
\code | ||||
import QtQuick 2.0 | ||||
import QtCharts 2.0 | ||||
ChartView { | ||||
title: "Box Plot series" | ||||
width: 400 | ||||
height: 300 | ||||
theme: ChartView.ChartThemeBrownSand | ||||
legend.alignment: Qt.AlignBottom | ||||
BoxPlotSeries { | ||||
id: plotSeries | ||||
name: "Income" | ||||
BoxSet { label: "Jan"; values: [3, 4, 5.1, 6.2, 8.5] } | ||||
BoxSet { label: "Feb"; values: [5, 6, 7.5, 8.6, 11.8] } | ||||
BoxSet { label: "Mar"; values: [3.2, 5, 5.7, 8, 9.2] } | ||||
BoxSet { label: "Apr"; values: [3.8, 5, 6.4, 7, 8] } | ||||
BoxSet { label: "May"; values: [4, 5, 5.2, 6, 7] } | ||||
} | ||||
} | ||||
\endcode | ||||
\beginfloatleft | ||||
\image examples_qmlboxplot.png | ||||
\endfloat | ||||
\clearfloat | ||||
\sa BoxSet, BarCategoryAxis | ||||
*/ | ||||
/*! | ||||
\qmlmethod BoxPlotSeries::append(string label, VariantList values) | ||||
Appends a new box-and-whiskers set with \a label and \a values to the series. | ||||
*/ | ||||
/*! | ||||
\qmlmethod BoxPlotSeries::append(BoxSet box) | ||||
Appends the \a box to the series. | ||||
*/ | ||||
/*! | ||||
\qmlmethod BoxPlotSeries::insert(int index, string label, VariantList values) | ||||
Inserts a new box-and-whiskers set with \a label and \a values at the \a index position. | ||||
*/ | ||||
/*! | ||||
\qmlmethod BoxPlotSeries::remove(QBoxSet boxset) | ||||
Removes the \a boxset from the series. | ||||
*/ | ||||
/*! | ||||
\qmlmethod BoxPlotSeries::clear() | ||||
Removes all boxsets from the series. Deletes removed sets. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxPlotSeries::onClicked(BoxSet boxset); | ||||
Signal is emitted when the user clicks the \a boxset on the chart. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxPlotSeries::onHovered(bool status, BoxSet boxset); | ||||
Signal is emitted when there is change in hover \a status over \a boxset. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxPlotSeries::onPressed(BoxSet boxset) | ||||
This signal is emitted when the user presses the \a boxset on the chart. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxPlotSeries::onReleased(BoxSet boxset) | ||||
This signal is emitted when the user releases the \a boxset on the chart. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxPlotSeries::onDoubleClicked(BoxSet boxset) | ||||
This signal is emitted when the user doubleclicks the \a boxset on the chart. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxPlotSeries::onCountChanged(); | ||||
Signal is emitted when there is change in count of box-and-whiskers items in the series. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxPlotSeries::onBoxsetsAdded() | ||||
Signal is emitted when new box-and-whiskers sets are added to the series. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxPlotSeries::onBoxsetsRemoved() | ||||
Signal is emitted when new box-and-whiskers sets are removed from the series. | ||||
*/ | ||||
/*! | ||||
\qmlproperty AbstractAxis BoxPlotSeries::axisX | ||||
The x axis used for the series. If you leave both axisX and axisXTop undefined, a BarCategoriesAxis is created for | ||||
the series. | ||||
\sa axisXTop | ||||
*/ | ||||
/*! | ||||
\qmlproperty AbstractAxis BoxPlotSeries::axisY | ||||
The y axis used for the series. If you leave both axisY and axisYRight undefined, a ValueAxis is created for | ||||
the series. | ||||
\sa axisYRight | ||||
*/ | ||||
/*! | ||||
\qmlproperty AbstractAxis BoxPlotSeries::axisXTop | ||||
The x axis used for the series, drawn on top of the chart view. Note that you can only provide either axisX or | ||||
axisXTop, but not both. | ||||
\sa axisX | ||||
*/ | ||||
/*! | ||||
\qmlproperty AbstractAxis BoxPlotSeries::axisYRight | ||||
The y axis used for the series, drawn to the right on the chart view. Note that you can only provide either axisY | ||||
or axisYRight, but not both. | ||||
\sa axisY | ||||
*/ | ||||
/*! | ||||
\qmlproperty bool BoxPlotSeries::boxOutlineVisible | ||||
This property configures the visibility of the middle box outline. | ||||
*/ | ||||
/*! | ||||
\qmlproperty qreal BoxPlotSeries::boxWidth | ||||
This property configures the width of the box-and-whiskers item. The value signifies the relative | ||||
width of the box-and-whiskers item inside its own slot. The value can between 0.0 and 1.0. Negative values | ||||
are clamped to 0.0 and values over 1.0 are clamped to 1.0. | ||||
*/ | ||||
/*! | ||||
\qmlproperty Pen BoxPlotSeries::pen | ||||
This property configures the pen of the box-and-whiskers items. | ||||
*/ | ||||
/*! | ||||
\qmlproperty Brush BoxPlotSeries::brush | ||||
This property configures the brush of the box-and-whiskers items. | ||||
*/ | ||||
/*! | ||||
\qmlproperty int BoxPlotSeries::count | ||||
The count of sets in series. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxPlotSeries::onBoxOutlineVisibilityChanged() | ||||
Signal is emitted when the middle box outline visibility is changed. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxPlotSeries::onBoxWidthChanged() | ||||
Signal is emitted when the width of the box-and-whiskers item is changed. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxPlotSeries::onPenChanged() | ||||
Signal is emitted when the pen for box-and-whiskers items has changed. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxPlotSeries::onBrushChanged() | ||||
Signal is emitted when the brush for box-and-whiskers items has changed. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxPlotSeries::onAxisXChanged(AbstractAxis axis) | ||||
Signal is emitted when there is change in X axis. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxPlotSeries::onAxisYChanged(AbstractAxis axis) | ||||
Signal is emitted when there is change in Y axis. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxPlotSeries::onAxisXTopChanged(AbstractAxis axis) | ||||
Signal is emitted when there is change in top X axis. | ||||
*/ | ||||
/*! | ||||
\qmlsignal BoxPlotSeries::onAxisYRightChanged(AbstractAxis axis) | ||||
Signal is emitted when there is change in Y right axis. | ||||
*/ | ||||
DeclarativeBoxSet::DeclarativeBoxSet(const QString label, QObject *parent) | ||||
: QBoxSet(label, parent) | ||||
{ | ||||
connect(this, SIGNAL(valuesChanged()), this, SIGNAL(changedValues())); | ||||
connect(this, SIGNAL(valueChanged(int)), this, SIGNAL(changedValue(int))); | ||||
connect(this, SIGNAL(brushChanged()), this, SLOT(handleBrushChanged())); | ||||
} | ||||
QVariantList DeclarativeBoxSet::values() | ||||
{ | ||||
QVariantList values; | ||||
for (int i(0); i < 5; i++) | ||||
values.append(QVariant(QBoxSet::at(i))); | ||||
return values; | ||||
} | ||||
void DeclarativeBoxSet::setValues(QVariantList values) | ||||
{ | ||||
for (int i(0); i < values.count(); i++) { | ||||
if (values.at(i).canConvert(QVariant::Double)) | ||||
QBoxSet::append(values[i].toDouble()); | ||||
} | ||||
} | ||||
QString DeclarativeBoxSet::brushFilename() const | ||||
{ | ||||
return m_brushFilename; | ||||
} | ||||
void DeclarativeBoxSet::setBrushFilename(const QString &brushFilename) | ||||
{ | ||||
QImage brushImage(brushFilename); | ||||
if (QBoxSet::brush().textureImage() != brushImage) { | ||||
QBrush brush = QBoxSet::brush(); | ||||
brush.setTextureImage(brushImage); | ||||
QBoxSet::setBrush(brush); | ||||
m_brushFilename = brushFilename; | ||||
m_brushImage = brushImage; | ||||
emit brushFilenameChanged(brushFilename); | ||||
} | ||||
} | ||||
void DeclarativeBoxSet::handleBrushChanged() | ||||
{ | ||||
// If the texture image of the brush has changed along the brush | ||||
// the brush file name needs to be cleared. | ||||
if (!m_brushFilename.isEmpty() && QBoxSet::brush().textureImage() != m_brushImage) { | ||||
m_brushFilename.clear(); | ||||
emit brushFilenameChanged(QString("")); | ||||
} | ||||
} | ||||
// ===================================================== | ||||
DeclarativeBoxPlotSeries::DeclarativeBoxPlotSeries(QQuickItem *parent) : | ||||
QBoxPlotSeries(parent), | ||||
m_axes(new DeclarativeAxes(this)) | ||||
{ | ||||
connect(m_axes, SIGNAL(axisXChanged(QAbstractAxis*)), this, SIGNAL(axisXChanged(QAbstractAxis*))); | ||||
connect(m_axes, SIGNAL(axisYChanged(QAbstractAxis*)), this, SIGNAL(axisYChanged(QAbstractAxis*))); | ||||
connect(m_axes, SIGNAL(axisXTopChanged(QAbstractAxis*)), this, SIGNAL(axisXTopChanged(QAbstractAxis*))); | ||||
connect(m_axes, SIGNAL(axisYRightChanged(QAbstractAxis*)), this, SIGNAL(axisYRightChanged(QAbstractAxis*))); | ||||
connect(this, SIGNAL(hovered(bool, QBoxSet*)), this, SLOT(onHovered(bool, QBoxSet*))); | ||||
connect(this, SIGNAL(clicked(QBoxSet*)), this, SLOT(onClicked(QBoxSet*))); | ||||
connect(this, SIGNAL(brushChanged()), this, SLOT(handleBrushChanged())); | ||||
connect(this, SIGNAL(pressed(QBoxSet*)), this, SLOT(onPressed(QBoxSet*))); | ||||
connect(this, SIGNAL(released(QBoxSet*)), this, SLOT(onReleased(QBoxSet*))); | ||||
connect(this, SIGNAL(doubleClicked(QBoxSet*)), this, SLOT(onDoubleClicked(QBoxSet*))); | ||||
} | ||||
void DeclarativeBoxPlotSeries::classBegin() | ||||
{ | ||||
} | ||||
void DeclarativeBoxPlotSeries::componentComplete() | ||||
{ | ||||
foreach (QObject *child, children()) { | ||||
if (qobject_cast<DeclarativeBoxSet *>(child)) { | ||||
QBoxPlotSeries::append(qobject_cast<DeclarativeBoxSet *>(child)); | ||||
} else if (qobject_cast<QVBoxPlotModelMapper *>(child)) { | ||||
QVBoxPlotModelMapper *mapper = qobject_cast<QVBoxPlotModelMapper *>(child); | ||||
mapper->setSeries(this); | ||||
} | ||||
} | ||||
} | ||||
QQmlListProperty<QObject> DeclarativeBoxPlotSeries::seriesChildren() | ||||
{ | ||||
return QQmlListProperty<QObject>(this, 0, &DeclarativeBoxPlotSeries::appendSeriesChildren ,0,0,0); | ||||
} | ||||
void DeclarativeBoxPlotSeries::appendSeriesChildren(QQmlListProperty<QObject> *list, QObject *element) | ||||
{ | ||||
// Empty implementation; the children are parsed in componentComplete instead | ||||
Q_UNUSED(list); | ||||
Q_UNUSED(element); | ||||
} | ||||
DeclarativeBoxSet *DeclarativeBoxPlotSeries::at(int index) | ||||
{ | ||||
QList<QBoxSet *> setList = boxSets(); | ||||
if (index >= 0 && index < setList.count()) | ||||
return qobject_cast<DeclarativeBoxSet *>(setList[index]); | ||||
return 0; | ||||
} | ||||
DeclarativeBoxSet *DeclarativeBoxPlotSeries::insert(int index, const QString label, QVariantList values) | ||||
{ | ||||
DeclarativeBoxSet *barset = new DeclarativeBoxSet(label, this); | ||||
barset->setValues(values); | ||||
if (QBoxPlotSeries::insert(index, barset)) | ||||
return barset; | ||||
delete barset; | ||||
return 0; | ||||
} | ||||
void DeclarativeBoxPlotSeries::onHovered(bool status, QBoxSet *boxset) | ||||
{ | ||||
emit hovered(status, qobject_cast<DeclarativeBoxSet *>(boxset)); | ||||
} | ||||
void DeclarativeBoxPlotSeries::onClicked(QBoxSet *boxset) | ||||
{ | ||||
emit clicked(qobject_cast<DeclarativeBoxSet *>(boxset)); | ||||
} | ||||
void DeclarativeBoxPlotSeries::onPressed(QBoxSet *boxset) | ||||
{ | ||||
emit pressed(qobject_cast<DeclarativeBoxSet *>(boxset)); | ||||
} | ||||
void DeclarativeBoxPlotSeries::onReleased(QBoxSet *boxset) | ||||
{ | ||||
emit released(qobject_cast<DeclarativeBoxSet *>(boxset)); | ||||
} | ||||
void DeclarativeBoxPlotSeries::onDoubleClicked(QBoxSet *boxset) | ||||
{ | ||||
emit doubleClicked(qobject_cast<DeclarativeBoxSet *>(boxset)); | ||||
} | ||||
QString DeclarativeBoxPlotSeries::brushFilename() const | ||||
{ | ||||
return m_brushFilename; | ||||
} | ||||
void DeclarativeBoxPlotSeries::setBrushFilename(const QString &brushFilename) | ||||
{ | ||||
QImage brushImage(brushFilename); | ||||
if (QBoxPlotSeries::brush().textureImage() != brushImage) { | ||||
QBrush brush = QBoxPlotSeries::brush(); | ||||
brush.setTextureImage(brushImage); | ||||
QBoxPlotSeries::setBrush(brush); | ||||
m_brushFilename = brushFilename; | ||||
m_brushImage = brushImage; | ||||
emit brushFilenameChanged(brushFilename); | ||||
} | ||||
} | ||||
void DeclarativeBoxPlotSeries::handleBrushChanged() | ||||
{ | ||||
// If the texture image of the brush has changed along the brush | ||||
// the brush file name needs to be cleared. | ||||
if (!m_brushFilename.isEmpty() && QBoxPlotSeries::brush().textureImage() != m_brushImage) { | ||||
m_brushFilename.clear(); | ||||
emit brushFilenameChanged(QString("")); | ||||
} | ||||
} | ||||
#include "moc_declarativeboxplotseries.cpp" | ||||
QT_CHARTS_END_NAMESPACE | ||||