1 | // Copyright (C) 2016 The Qt Company Ltd. |
---|---|
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses |
5 | |
6 | #include "declarativebarseries_p.h" |
7 | #include "declarativeboxplotseries_p.h" |
8 | #include <QtCharts/QBoxSet> |
9 | #include <QtCharts/QHBoxPlotModelMapper> |
10 | #include <QtCharts/QVBoxPlotModelMapper> |
11 | |
12 | QT_BEGIN_NAMESPACE |
13 | |
14 | /*! |
15 | \qmltype BoxSet |
16 | \nativetype QBoxSet |
17 | \inqmlmodule QtCharts |
18 | |
19 | \brief Represents one item in a box-and-whiskers chart. |
20 | |
21 | A box-and-whiskers item is a graphical representation of a range and three median values |
22 | that is constructed from five different values. There are two ways to specify the values. |
23 | The first one is by using a constructor or the append() method. The values have to be |
24 | specified in the following order: lower extreme, lower quartile, median, upper quartile, |
25 | and upper extreme. |
26 | |
27 | The second way is to create an empty BoxSet instance and specify the values using the |
28 | setValue() method. |
29 | |
30 | \sa BoxPlotSeries |
31 | */ |
32 | |
33 | /*! |
34 | \qmlproperty list BoxSet::values |
35 | The values of the box-and-whiskers item. The following enumerations can be |
36 | used as indexes when accessing the list of values: |
37 | |
38 | \value BoxSet.LowerExtreme The smallest value of the box-and-whiskers item. |
39 | \value BoxSet.LowerQuartile The median value of the lower half of the box-and-whiskers item. |
40 | \value BoxSet.Median The median value of the box-and-whiskers item. |
41 | \value BoxSet.UpperQuartile The median value of the upper half of the box-and-whiskers item. |
42 | \value BoxSet.UpperExtreme The largest value of the box-and-whiskers item. |
43 | |
44 | \sa at(), setValue() |
45 | */ |
46 | /*! |
47 | \qmlproperty string BoxSet::label |
48 | The label of the category of the box-and-whiskers item. |
49 | */ |
50 | /*! |
51 | \qmlproperty int BoxSet::count |
52 | The number of values of the box-and-whiskers item. |
53 | */ |
54 | |
55 | /*! |
56 | \qmlproperty string BoxSet::brushFilename |
57 | The name of the file used as a brush for the box-and-whiskers item. |
58 | */ |
59 | |
60 | /*! |
61 | \qmlmethod void BoxSet::at(int index) |
62 | Returns the value in the position specified by \a index. |
63 | */ |
64 | /*! |
65 | \qmlmethod void BoxSet::append(qreal value) |
66 | Appends the new value specified by \a value to the end of the box-and-whiskers item. |
67 | */ |
68 | /*! |
69 | \qmlmethod void BoxSet::clear() |
70 | Sets all the values of the box-and-whiskers item to 0. |
71 | */ |
72 | /*! |
73 | \qmlmethod void BoxSet::setValue(int index, qreal value) |
74 | Sets the value specified by \a value in the position specified by \a index. |
75 | */ |
76 | /*! |
77 | \qmlsignal BoxSet::clicked() |
78 | This signal is emitted when the user clicks a box-and-whiskers item in the chart. |
79 | |
80 | The corresponding signal handler is \c onClicked(). |
81 | */ |
82 | /*! |
83 | \qmlsignal BoxSet::pressed() |
84 | This signal is emitted when the user clicks a box-and-whiskers item in the chart |
85 | and holds down the mouse button. |
86 | |
87 | The corresponding signal handler is \c onPressed. |
88 | */ |
89 | /*! |
90 | \qmlsignal BoxSet::released() |
91 | This signal is emitted when the user releases the mouse press on a box-and-whiskers item. |
92 | |
93 | The corresponding signal handler is \c onReleased(). |
94 | */ |
95 | /*! |
96 | \qmlsignal BoxSet::doubleClicked() |
97 | This signal is emitted when the user double-clicks a box-and-whiskers item. |
98 | |
99 | The corresponding signal handler is \c onDoubleClicked(). |
100 | */ |
101 | /*! |
102 | \qmlsignal BoxSet::hovered(bool status) |
103 | This signal is emitted when a mouse is hovered over a box-and-whiskers item in a chart. |
104 | When the mouse moves over the item, \a status turns \c true, and when the mouse moves |
105 | away again, it turns \c false. |
106 | |
107 | The corresponding signal handler is \c onHovered(). |
108 | */ |
109 | /*! |
110 | \qmlsignal BoxSet::valuesChanged() |
111 | This signal is emitted when multiple values of the box-and-whiskers item change. |
112 | |
113 | The corresponding signal handler is \c onValuesChanged(). |
114 | */ |
115 | /*! |
116 | \qmlsignal BoxSet::valueChanged(int index) |
117 | This signal is emitted when the value of the box-and-whiskers item specified by \a index |
118 | changes. |
119 | |
120 | The corresponding signal handler is \c onValueChanged(). |
121 | */ |
122 | /*! |
123 | \qmlsignal BoxSet::cleared() |
124 | This signal is emitted when all the values of the box-and-whiskers item are set to 0. |
125 | |
126 | The corresponding signal handler is \c onCleared(). |
127 | */ |
128 | |
129 | /*! |
130 | \qmltype BoxPlotSeries |
131 | \nativetype QBoxPlotSeries |
132 | \inqmlmodule QtCharts |
133 | |
134 | \inherits AbstractSeries |
135 | |
136 | \brief Presents data in box-and-whiskers charts. |
137 | |
138 | A box plot series acts as a container for box-and-whiskers items. Items from multiple series |
139 | are grouped into categories according to their index value. |
140 | |
141 | The BarCategoryAxis class is used to add the categories to the chart's axis. Category labels |
142 | have to be unique. If the same category label is defined for several box-and-whiskers items, |
143 | only the first one is drawn. |
144 | |
145 | The following QML code snippet shows how to create a simple box-and-whiskers chart: |
146 | \code |
147 | import QtQuick 2.0 |
148 | import QtCharts 2.0 |
149 | |
150 | ChartView { |
151 | title: "Box Plot series" |
152 | width: 400 |
153 | height: 300 |
154 | theme: ChartView.ChartThemeBrownSand |
155 | legend.alignment: Qt.AlignBottom |
156 | |
157 | BoxPlotSeries { |
158 | id: plotSeries |
159 | name: "Income" |
160 | BoxSet { label: "Jan"; values: [3, 4, 5.1, 6.2, 8.5] } |
161 | BoxSet { label: "Feb"; values: [5, 6, 7.5, 8.6, 11.8] } |
162 | BoxSet { label: "Mar"; values: [3.2, 5, 5.7, 8, 9.2] } |
163 | BoxSet { label: "Apr"; values: [3.8, 5, 6.4, 7, 8] } |
164 | BoxSet { label: "May"; values: [4, 5, 5.2, 6, 7] } |
165 | } |
166 | } |
167 | \endcode |
168 | |
169 | \beginfloatleft |
170 | \image examples_qmlboxplot.png |
171 | \endfloat |
172 | \clearfloat |
173 | |
174 | \sa BoxSet, BarCategoryAxis |
175 | */ |
176 | |
177 | /*! |
178 | \qmlmethod BoxPlotSeries::at(int index) |
179 | Returns the box-and-whiskers item in the position specified by \a index. |
180 | */ |
181 | |
182 | /*! |
183 | \qmlmethod BoxPlotSeries::append(string label, VariantList values) |
184 | Appends a new box-and-whiskers item with the label specified by \a label and the values |
185 | specified by \a values to the series. |
186 | */ |
187 | /*! |
188 | \qmlmethod BoxPlotSeries::append(BoxSet box) |
189 | Appends the box-and-whiskers item specified by \a box to the series. |
190 | */ |
191 | /*! |
192 | \qmlmethod BoxPlotSeries::insert(int index, string label, VariantList values) |
193 | Inserts a new box-and-whiskers item with the label specified by \a label and the values |
194 | specified by \a values to the series at the position specified by \a index. |
195 | */ |
196 | /*! |
197 | \qmlmethod BoxPlotSeries::remove(QBoxSet boxset) |
198 | Removes the box-and-whiskers item specified by \a boxset from the series. |
199 | */ |
200 | /*! |
201 | \qmlmethod BoxPlotSeries::clear() |
202 | Removes all box-and-whiskers items from the series and permanently deletes them. |
203 | */ |
204 | /*! |
205 | \qmlsignal BoxPlotSeries::clicked(BoxSet boxset); |
206 | This signal is emitted when the user clicks the box-and-whiskers item specified by |
207 | \a boxset in the chart. |
208 | |
209 | The corresponding signal handler is \c onClicked(). |
210 | */ |
211 | /*! |
212 | \qmlsignal BoxPlotSeries::hovered(bool status, BoxSet boxset); |
213 | This signal is emitted when a mouse is hovered over the box-and-whiskers item specified by |
214 | \a boxset in the chart. When the mouse moves over the item, \a status turns \c true, and |
215 | when the mouse moves away again, it turns \c false. |
216 | |
217 | The corresponding signal handler is \c onHovered(). |
218 | */ |
219 | /*! |
220 | \qmlsignal BoxPlotSeries::pressed(BoxSet boxset) |
221 | This signal is emitted when the user presses the \a boxset on the chart. |
222 | |
223 | The corresponding signal handler is \c onPressed. |
224 | */ |
225 | /*! |
226 | \qmlsignal BoxPlotSeries::released(BoxSet boxset) |
227 | This signal is emitted when the user releases the mouse press on the box-and-whiskers |
228 | item specified by \a boxset in the chart. |
229 | |
230 | The corresponding signal handler is \c onReleased(). |
231 | */ |
232 | /*! |
233 | \qmlsignal BoxPlotSeries::doubleClicked(BoxSet boxset) |
234 | This signal is emitted when the user double-clicks the box-and-whiskers item specified by |
235 | \a boxset in the chart. |
236 | |
237 | The corresponding signal handler is \c onDoubleClicked(). |
238 | */ |
239 | /*! |
240 | \qmlsignal BoxPlotSeries::boxsetsAdded(list sets) |
241 | This signal is emitted when the box-and-whiskers items specified by \a sets |
242 | are added to the series. |
243 | |
244 | The corresponding signal handler is \c onBoxsetsAdded(). |
245 | */ |
246 | /*! |
247 | \qmlsignal BoxPlotSeries::boxsetsRemoved(list sets) |
248 | This signal is emitted when the box-and-whiskers items specified by \a sets |
249 | are removed from the series. |
250 | |
251 | The corresponding signal handler is \c onBoxsetsRemoved(). |
252 | */ |
253 | /*! |
254 | \qmlproperty AbstractAxis BoxPlotSeries::axisX |
255 | The x-axis used for the series. If you leave both axisX and axisXTop undefined, a |
256 | BarCategoryAxis is created for the series. |
257 | \sa axisXTop |
258 | */ |
259 | /*! |
260 | \qmlproperty AbstractAxis BoxPlotSeries::axisY |
261 | The y-axis used for the series. If you leave both axisY and axisYRight undefined, a |
262 | ValueAxis is created for the series. |
263 | \sa axisYRight |
264 | */ |
265 | /*! |
266 | \qmlproperty AbstractAxis BoxPlotSeries::axisXTop |
267 | The x-axis used for the series, drawn on top of the chart view. |
268 | |
269 | \note You can only provide either axisX or axisXTop, but not both. |
270 | \sa axisX |
271 | |
272 | \sa axisX |
273 | */ |
274 | /*! |
275 | \qmlproperty AbstractAxis BoxPlotSeries::axisYRight |
276 | The y-axis used for the series, drawn to the right on the chart view. |
277 | |
278 | \note You can only provide either axisY or axisYRight, but not both. |
279 | \sa axisY |
280 | */ |
281 | /*! |
282 | \qmlproperty bool BoxPlotSeries::boxOutlineVisible |
283 | The visibility of the box outline. |
284 | */ |
285 | /*! |
286 | \qmlproperty real BoxPlotSeries::boxWidth |
287 | \brief The width of the box-and-whiskers item. The value indicates the relative |
288 | width of the item within its category. The value can be between 0.0 and 1.0. Negative values |
289 | are replaced with 0.0 and values greater than 1.0 are replaced with 1.0. |
290 | */ |
291 | |
292 | /*! |
293 | \qmlproperty string BoxPlotSeries::brushFilename |
294 | The name of the file used as a brush for the series. |
295 | */ |
296 | |
297 | /*! |
298 | \qmlproperty int BoxPlotSeries::count |
299 | The number of box-and-whiskers items in a box plot series. |
300 | */ |
301 | |
302 | |
303 | DeclarativeBoxSet::DeclarativeBoxSet(const QString label, QObject *parent) |
304 | : QBoxSet(label, parent) |
305 | { |
306 | connect(sender: this, SIGNAL(valuesChanged()), receiver: this, SIGNAL(changedValues())); |
307 | connect(sender: this, SIGNAL(valueChanged(int)), receiver: this, SIGNAL(changedValue(int))); |
308 | connect(sender: this, SIGNAL(brushChanged()), receiver: this, SLOT(handleBrushChanged())); |
309 | } |
310 | |
311 | QVariantList DeclarativeBoxSet::values() |
312 | { |
313 | QVariantList values; |
314 | for (int i(0); i < 5; i++) |
315 | values.append(t: QVariant(QBoxSet::at(index: i))); |
316 | return values; |
317 | } |
318 | |
319 | void DeclarativeBoxSet::setValues(QVariantList values) |
320 | { |
321 | for (int i(0); i < values.size(); i++) { |
322 | if (values.at(i).canConvert<double>()) |
323 | QBoxSet::append(value: values[i].toDouble()); |
324 | } |
325 | } |
326 | |
327 | QString DeclarativeBoxSet::brushFilename() const |
328 | { |
329 | return m_brushFilename; |
330 | } |
331 | |
332 | void DeclarativeBoxSet::setBrushFilename(const QString &brushFilename) |
333 | { |
334 | QImage brushImage(brushFilename); |
335 | if (QBoxSet::brush().textureImage() != brushImage) { |
336 | QBrush brush = QBoxSet::brush(); |
337 | brush.setTextureImage(brushImage); |
338 | QBoxSet::setBrush(brush); |
339 | m_brushFilename = brushFilename; |
340 | m_brushImage = brushImage; |
341 | emit brushFilenameChanged(brushFilename); |
342 | } |
343 | } |
344 | |
345 | void DeclarativeBoxSet::handleBrushChanged() |
346 | { |
347 | // If the texture image of the brush has changed along the brush |
348 | // the brush file name needs to be cleared. |
349 | if (!m_brushFilename.isEmpty() && QBoxSet::brush().textureImage() != m_brushImage) { |
350 | m_brushFilename.clear(); |
351 | emit brushFilenameChanged(brushFilename: QString()); |
352 | } |
353 | } |
354 | |
355 | // ===================================================== |
356 | |
357 | DeclarativeBoxPlotSeries::DeclarativeBoxPlotSeries(QQuickItem *parent) : |
358 | QBoxPlotSeries(parent), |
359 | m_axes(new DeclarativeAxes(this)) |
360 | { |
361 | connect(sender: m_axes, SIGNAL(axisXChanged(QAbstractAxis*)), receiver: this, SIGNAL(axisXChanged(QAbstractAxis*))); |
362 | connect(sender: m_axes, SIGNAL(axisYChanged(QAbstractAxis*)), receiver: this, SIGNAL(axisYChanged(QAbstractAxis*))); |
363 | connect(sender: m_axes, SIGNAL(axisXTopChanged(QAbstractAxis*)), receiver: this, SIGNAL(axisXTopChanged(QAbstractAxis*))); |
364 | connect(sender: m_axes, SIGNAL(axisYRightChanged(QAbstractAxis*)), receiver: this, SIGNAL(axisYRightChanged(QAbstractAxis*))); |
365 | connect(sender: this, SIGNAL(hovered(bool, QBoxSet*)), receiver: this, SLOT(onHovered(bool, QBoxSet*))); |
366 | connect(sender: this, SIGNAL(clicked(QBoxSet*)), receiver: this, SLOT(onClicked(QBoxSet*))); |
367 | connect(sender: this, SIGNAL(brushChanged()), receiver: this, SLOT(handleBrushChanged())); |
368 | connect(sender: this, SIGNAL(pressed(QBoxSet*)), receiver: this, SLOT(onPressed(QBoxSet*))); |
369 | connect(sender: this, SIGNAL(released(QBoxSet*)), receiver: this, SLOT(onReleased(QBoxSet*))); |
370 | connect(sender: this, SIGNAL(doubleClicked(QBoxSet*)), receiver: this, SLOT(onDoubleClicked(QBoxSet*))); |
371 | } |
372 | |
373 | void DeclarativeBoxPlotSeries::classBegin() |
374 | { |
375 | } |
376 | |
377 | void DeclarativeBoxPlotSeries::componentComplete() |
378 | { |
379 | foreach (QObject *child, children()) { |
380 | if (qobject_cast<DeclarativeBoxSet *>(object: child)) { |
381 | QBoxPlotSeries::append(box: qobject_cast<DeclarativeBoxSet *>(object: child)); |
382 | } else if (qobject_cast<QVBoxPlotModelMapper *>(object: child)) { |
383 | QVBoxPlotModelMapper *mapper = qobject_cast<QVBoxPlotModelMapper *>(object: child); |
384 | mapper->setSeries(this); |
385 | } else if (QHBoxPlotModelMapper *mapper = qobject_cast<QHBoxPlotModelMapper *>(object: child)) { |
386 | mapper->setSeries(this); |
387 | } |
388 | } |
389 | } |
390 | |
391 | QQmlListProperty<QObject> DeclarativeBoxPlotSeries::seriesChildren() |
392 | { |
393 | return QQmlListProperty<QObject>(this, 0, &DeclarativeBoxPlotSeries::appendSeriesChildren ,0,0,0); |
394 | } |
395 | |
396 | void DeclarativeBoxPlotSeries::appendSeriesChildren(QQmlListProperty<QObject> *list, QObject *element) |
397 | { |
398 | // Empty implementation; the children are parsed in componentComplete instead |
399 | Q_UNUSED(list); |
400 | Q_UNUSED(element); |
401 | } |
402 | |
403 | DeclarativeBoxSet *DeclarativeBoxPlotSeries::at(int index) |
404 | { |
405 | QList<QBoxSet *> setList = boxSets(); |
406 | if (index >= 0 && index < setList.size()) |
407 | return qobject_cast<DeclarativeBoxSet *>(object: setList[index]); |
408 | |
409 | return 0; |
410 | } |
411 | |
412 | DeclarativeBoxSet *DeclarativeBoxPlotSeries::insert(int index, const QString label, QVariantList values) |
413 | { |
414 | DeclarativeBoxSet *barset = new DeclarativeBoxSet(label, this); |
415 | barset->setValues(values); |
416 | if (QBoxPlotSeries::insert(index, box: barset)) |
417 | return barset; |
418 | delete barset; |
419 | return 0; |
420 | } |
421 | |
422 | void DeclarativeBoxPlotSeries::onHovered(bool status, QBoxSet *boxset) |
423 | { |
424 | emit hovered(status, boxset: qobject_cast<DeclarativeBoxSet *>(object: boxset)); |
425 | } |
426 | |
427 | void DeclarativeBoxPlotSeries::onClicked(QBoxSet *boxset) |
428 | { |
429 | emit clicked(boxset: qobject_cast<DeclarativeBoxSet *>(object: boxset)); |
430 | } |
431 | |
432 | void DeclarativeBoxPlotSeries::onPressed(QBoxSet *boxset) |
433 | { |
434 | emit pressed(boxset: qobject_cast<DeclarativeBoxSet *>(object: boxset)); |
435 | } |
436 | |
437 | void DeclarativeBoxPlotSeries::onReleased(QBoxSet *boxset) |
438 | { |
439 | emit released(boxset: qobject_cast<DeclarativeBoxSet *>(object: boxset)); |
440 | } |
441 | |
442 | void DeclarativeBoxPlotSeries::onDoubleClicked(QBoxSet *boxset) |
443 | { |
444 | emit doubleClicked(boxset: qobject_cast<DeclarativeBoxSet *>(object: boxset)); |
445 | } |
446 | |
447 | QString DeclarativeBoxPlotSeries::brushFilename() const |
448 | { |
449 | return m_brushFilename; |
450 | } |
451 | |
452 | void DeclarativeBoxPlotSeries::setBrushFilename(const QString &brushFilename) |
453 | { |
454 | QImage brushImage(brushFilename); |
455 | if (QBoxPlotSeries::brush().textureImage() != brushImage) { |
456 | QBrush brush = QBoxPlotSeries::brush(); |
457 | brush.setTextureImage(brushImage); |
458 | QBoxPlotSeries::setBrush(brush); |
459 | m_brushFilename = brushFilename; |
460 | m_brushImage = brushImage; |
461 | emit brushFilenameChanged(brushFilename); |
462 | } |
463 | } |
464 | |
465 | void DeclarativeBoxPlotSeries::handleBrushChanged() |
466 | { |
467 | // If the texture image of the brush has changed along the brush |
468 | // the brush file name needs to be cleared. |
469 | if (!m_brushFilename.isEmpty() && QBoxPlotSeries::brush().textureImage() != m_brushImage) { |
470 | m_brushFilename.clear(); |
471 | emit brushFilenameChanged(brushFilename: QString()); |
472 | } |
473 | } |
474 | |
475 | QT_END_NAMESPACE |
476 | |
477 | #include "moc_declarativeboxplotseries_p.cpp" |
478 |
Definitions
Learn Advanced QML with KDAB
Find out more