declarativeboxplotseries.cpp
468 lines
| 15.4 KiB
| text/x-c
|
CppLexer
Titta Heikkala
|
r2845 | /****************************************************************************** | ||
Mika Salmela
|
r2548 | ** | ||
Titta Heikkala
|
r2845 | ** Copyright (C) 2015 The Qt Company Ltd. | ||
** Contact: http://www.qt.io/licensing/ | ||||
Mika Salmela
|
r2548 | ** | ||
Titta Heikkala
|
r2740 | ** This file is part of the Qt Charts module. | ||
Mika Salmela
|
r2548 | ** | ||
Titta Heikkala
|
r2845 | ** $QT_BEGIN_LICENSE:COMM$ | ||
Mika Salmela
|
r2548 | ** | ||
Titta Heikkala
|
r2845 | ** 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 http://www.qt.io/terms-conditions. For further | ||||
** information use the contact form at http://www.qt.io/contact-us. | ||||
Mika Salmela
|
r2548 | ** | ||
Titta Heikkala
|
r2845 | ** $QT_END_LICENSE$ | ||
** | ||||
******************************************************************************/ | ||||
Mika Salmela
|
r2548 | |||
#include "declarativebarseries.h" | ||||
#include "declarativeboxplotseries.h" | ||||
Titta Heikkala
|
r2714 | #include <QtCharts/QBoxSet> | ||
#include <QtCharts/QVBoxPlotModelMapper> | ||||
Mika Salmela
|
r2548 | |||
Titta Heikkala
|
r2712 | QT_CHARTS_BEGIN_NAMESPACE | ||
Mika Salmela
|
r2548 | |||
Titta Heikkala
|
r2639 | /*! | ||
\qmltype BoxSet | ||||
\instantiates QBoxSet | ||||
Titta Heikkala
|
r2712 | \inqmlmodule QtCharts | ||
Titta Heikkala
|
r2639 | |||
Titta Heikkala
|
r2727 | \brief Building block for box-and-whiskers chart. | ||
Titta Heikkala
|
r2712 | 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 | ||||
Titta Heikkala
|
r2639 | */ | ||
Mika Salmela
|
r2573 | /*! | ||
\qmlproperty string BoxSet::values | ||||
The values on the box-and-whiskers set. | ||||
*/ | ||||
/*! | ||||
\qmlproperty string BoxSet::label | ||||
Titta Heikkala
|
r2812 | Defines the label of the category of the box-and-whiskers set. | ||
Mika Salmela
|
r2573 | */ | ||
/*! | ||||
\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. | ||||
*/ | ||||
Titta Heikkala
|
r2739 | /*! | ||
\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. | ||||
*/ | ||||
Mika Salmela
|
r2573 | /*! | ||
\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. | ||||
*/ | ||||
/*! | ||||
Titta Heikkala
|
r2639 | \qmltype BoxPlotSeries | ||
\instantiates QBoxPlotSeries | ||||
Titta Heikkala
|
r2712 | \inqmlmodule QtCharts | ||
\inherits AbstractSeries | ||||
Titta Heikkala
|
r2727 | \brief Series for creating box-and-whiskers chart. | ||
Titta Heikkala
|
r2712 | 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. | ||||
Titta Heikkala
|
r2812 | \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. | ||||
Titta Heikkala
|
r2712 | 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 | ||||
Mika Salmela
|
r2573 | |||
Titta Heikkala
|
r2712 | \beginfloatleft | ||
\image examples_qmlboxplot.png | ||||
\endfloat | ||||
\clearfloat | ||||
Titta Heikkala
|
r2812 | |||
\sa BoxSet, BarCategoryAxis | ||||
Mika Salmela
|
r2573 | */ | ||
Titta Heikkala
|
r2639 | |||
Mika Salmela
|
r2573 | /*! | ||
\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. | ||||
*/ | ||||
Titta Heikkala
|
r2756 | /*! | ||
\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. | ||||
*/ | ||||
Mika Salmela
|
r2573 | /*! | ||
\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. | ||||
*/ | ||||
Mika Salmela
|
r2584 | /*! | ||
\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. | ||||
*/ | ||||
Mika Salmela
|
r2573 | /*! | ||
\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. | ||||
*/ | ||||
Titta Heikkala
|
r2682 | /*! | ||
\qmlproperty int BoxPlotSeries::count | ||||
The count of sets in series. | ||||
*/ | ||||
Mika Salmela
|
r2573 | /*! | ||
\qmlsignal BoxPlotSeries::onBoxOutlineVisibilityChanged() | ||||
Signal is emitted when the middle box outline visibility is changed. | ||||
*/ | ||||
Mika Salmela
|
r2584 | /*! | ||
\qmlsignal BoxPlotSeries::onBoxWidthChanged() | ||||
Signal is emitted when the width of the box-and-whiskers item is changed. | ||||
*/ | ||||
Mika Salmela
|
r2573 | /*! | ||
\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. | ||||
*/ | ||||
Mika Salmela
|
r2548 | 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))); | ||||
Titta Heikkala
|
r2681 | connect(this, SIGNAL(brushChanged()), this, SLOT(handleBrushChanged())); | ||
Mika Salmela
|
r2548 | } | ||
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()); | ||||
} | ||||
} | ||||
Titta Heikkala
|
r2681 | 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("")); | ||||
} | ||||
} | ||||
Mika Salmela
|
r2548 | // ===================================================== | ||
Titta Heikkala
|
r2712 | DeclarativeBoxPlotSeries::DeclarativeBoxPlotSeries(QQuickItem *parent) : | ||
Mika Salmela
|
r2548 | 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*))); | ||||
Titta Heikkala
|
r2681 | connect(this, SIGNAL(brushChanged()), this, SLOT(handleBrushChanged())); | ||
Titta Heikkala
|
r2739 | 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*))); | ||||
Mika Salmela
|
r2548 | } | ||
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); | ||||
} | ||||
} | ||||
} | ||||
Titta Heikkala
|
r2712 | QQmlListProperty<QObject> DeclarativeBoxPlotSeries::seriesChildren() | ||
Mika Salmela
|
r2548 | { | ||
Titta Heikkala
|
r2712 | return QQmlListProperty<QObject>(this, 0, &DeclarativeBoxPlotSeries::appendSeriesChildren ,0,0,0); | ||
Mika Salmela
|
r2548 | } | ||
Titta Heikkala
|
r2712 | void DeclarativeBoxPlotSeries::appendSeriesChildren(QQmlListProperty<QObject> *list, QObject *element) | ||
Mika Salmela
|
r2548 | { | ||
// 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)); | ||||
} | ||||
Titta Heikkala
|
r2739 | 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)); | ||||
} | ||||
Titta Heikkala
|
r2681 | 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("")); | ||||
} | ||||
} | ||||
Mika Salmela
|
r2548 | #include "moc_declarativeboxplotseries.cpp" | ||
Titta Heikkala
|
r2712 | QT_CHARTS_END_NAMESPACE | ||