1 | // Copyright (C) 2024 The Qt Company Ltd. |
---|---|
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include <QtGraphs/qpieseries.h> |
5 | #include <private/qpieseries_p.h> |
6 | #include <QtGraphs/qpieslice.h> |
7 | #include <private/qpieslice_p.h> |
8 | |
9 | QT_BEGIN_NAMESPACE |
10 | |
11 | /*! |
12 | \class QPieSeries |
13 | \inmodule QtGraphs |
14 | \ingroup graphs_2D |
15 | \brief The QPieSeries class presents data in pie graphs. |
16 | |
17 | A pie series consists of slices that are defined as QPieSlice objects. |
18 | The slices can have any values as the QPieSeries object calculates |
19 | the percentage of a slice compared with the sum of all slices in the series |
20 | to determine the actual size of the slice in the graph. |
21 | |
22 | Pie size and position on the graph are controlled by using relative values |
23 | that range from 0.0 to 1.0. |
24 | These relate to the actual graph rectangle. |
25 | |
26 | By default, the pie is defined as a full pie. A partial pie can be created |
27 | by setting a starting angle and angle span for the series. |
28 | A full pie is 360 degrees, where 0 is at 12 a'clock. |
29 | |
30 | \sa QPieSlice |
31 | */ |
32 | /*! |
33 | \qmltype PieSeries |
34 | \nativetype QPieSeries |
35 | \inqmlmodule QtGraphs |
36 | \ingroup graphs_qml_2D |
37 | \inherits AbstractSeries |
38 | |
39 | \brief Presents data in pie graphs. |
40 | |
41 | A pie series consists of slices that are defined using the PieSlice type. |
42 | The slices can have any values as the PieSeries type calculates |
43 | the percentage of a slice compared with the sum of all slices in the series |
44 | to determine the actual size of the slice in the graph. |
45 | |
46 | Pie size and position on the graph are controlled by using relative values |
47 | that range from 0.0 to 1.0. |
48 | These relate to the actual graph rectangle. |
49 | |
50 | By default, the pie is defined as a full pie. A partial pie can be created |
51 | by setting a starting angle and angle span for the series. |
52 | A full pie is 360 degrees, where 0 is at 12 o'clock. |
53 | |
54 | The following QML example shows how to create a simple pie graph. |
55 | \qml |
56 | import QtQuick |
57 | import QtGraphs |
58 | |
59 | Item { |
60 | id: mainView |
61 | width: 1280 |
62 | height: 720 |
63 | |
64 | GraphsView { |
65 | anchors.fill: parent |
66 | theme: GraphsTheme { |
67 | colorScheme: GraphsTheme.ColorScheme.Dark |
68 | theme: GraphsTheme.Theme.QtGreen |
69 | } |
70 | PieSeries { |
71 | id: pieSeries |
72 | PieSlice { |
73 | value: 1 |
74 | } |
75 | PieSlice { |
76 | value: 2 |
77 | } |
78 | } |
79 | } |
80 | } |
81 | \endqml |
82 | |
83 | \sa PieSlice, GraphsView |
84 | */ |
85 | |
86 | /*! |
87 | \property QPieSeries::horizontalPosition |
88 | \brief The horizontal position of the pie. |
89 | |
90 | The value is relative to the graph rectangle, so that: |
91 | |
92 | \list |
93 | \li 0.0 is the absolute left. |
94 | \li 1.0 is the absolute right. |
95 | \endlist |
96 | The default value is 0.5 (center). |
97 | \sa verticalPosition |
98 | */ |
99 | |
100 | /*! |
101 | \qmlproperty real PieSeries::horizontalPosition |
102 | |
103 | The horizontal position of the pie. |
104 | |
105 | The value is relative to the graph rectangle, so that: |
106 | |
107 | \list |
108 | \li 0.0 is the absolute left. |
109 | \li 1.0 is the absolute right. |
110 | \endlist |
111 | The default value is 0.5 (center). |
112 | \sa verticalPosition |
113 | */ |
114 | |
115 | /*! |
116 | \qmlsignal PieSeries::horizontalPositionChanged() |
117 | This signal is emitted when the horizontal position changes. |
118 | \sa horizontalPosition |
119 | */ |
120 | |
121 | /*! |
122 | \property QPieSeries::verticalPosition |
123 | \brief The vertical position of the pie. |
124 | |
125 | The value is relative to the graph rectangle, so that: |
126 | |
127 | \list |
128 | \li 0.0 is the absolute top. |
129 | \li 1.0 is the absolute bottom. |
130 | \endlist |
131 | The default value is 0.5 (center). |
132 | \sa horizontalPosition |
133 | */ |
134 | |
135 | /*! |
136 | \qmlproperty real PieSeries::verticalPosition |
137 | |
138 | The vertical position of the pie. |
139 | |
140 | The value is relative to the graph rectangle, so that: |
141 | |
142 | \list |
143 | \li 0.0 is the absolute top. |
144 | \li 1.0 is the absolute bottom. |
145 | \endlist |
146 | The default value is 0.5 (center). |
147 | \sa horizontalPosition |
148 | */ |
149 | /*! |
150 | \qmlsignal PieSeries::verticalPositionChanged() |
151 | This signal is emitted when the vertical position changes. |
152 | \sa verticalPosition |
153 | */ |
154 | |
155 | /*! |
156 | \property QPieSeries::pieSize |
157 | \brief The pie size. |
158 | |
159 | The value is relative to the graph rectangle, so that: |
160 | |
161 | \list |
162 | \li 0.0 is the minimum pieSize (pie not drawn). |
163 | \li 1.0 is the maximum pieSize that can fit the graph. |
164 | \endlist |
165 | |
166 | When setting this property, the holeSize property is adjusted if necessary, |
167 | to ensure that the hole size is not greater than the pie size. |
168 | |
169 | The default value is 0.7. |
170 | */ |
171 | |
172 | /*! |
173 | \qmlproperty real PieSeries::pieSize |
174 | |
175 | The pie size. |
176 | |
177 | The value is relative to the graph rectangle, so that: |
178 | |
179 | \list |
180 | \li 0.0 is the minimum pieSize (pie not drawn). |
181 | \li 1.0 is the maximum pieSize that can fit the graph. |
182 | \endlist |
183 | |
184 | When setting this property, the holeSize property is adjusted if necessary, |
185 | to ensure that the hole size is not greater than the pie size. |
186 | |
187 | The default value is 0.7. |
188 | */ |
189 | /*! |
190 | \qmlsignal PieSeries::pieSizeChanged() |
191 | This signal is emitted when the pie size changes. |
192 | \sa pieSize |
193 | */ |
194 | |
195 | /*! |
196 | \property QPieSeries::holeSize |
197 | \brief The donut hole size. |
198 | |
199 | When setting the \l pieSize property, this property is adjusted if necessary, |
200 | to ensure that the hole size is not greater than the pie size. |
201 | |
202 | The default value is 0.0. |
203 | */ |
204 | |
205 | /*! |
206 | \qmlproperty real PieSeries::holeSize |
207 | |
208 | The donut hole size. |
209 | |
210 | When setting the \l pieSize property, this property is adjusted if necessary, |
211 | to ensure that the hole size is not greater than the pie size. |
212 | |
213 | The default value is 0.0. |
214 | |
215 | */ |
216 | /*! |
217 | \qmlsignal PieSeries::holeSizeChanged() |
218 | This signal is emitted when the donut hole size changes. |
219 | \sa holeSize |
220 | */ |
221 | |
222 | /*! |
223 | \property QPieSeries::startAngle |
224 | \brief The starting angle of the pie. |
225 | |
226 | A full pie is 360 degrees, where 0 degrees is at 12 o'clock. |
227 | |
228 | The default value is 0. |
229 | */ |
230 | |
231 | /*! |
232 | \qmlproperty real PieSeries::startAngle |
233 | |
234 | The starting angle of the pie. |
235 | |
236 | A full pie is 360 degrees, where 0 degrees is at 12 o'clock. |
237 | |
238 | The default value is 0. |
239 | */ |
240 | /*! |
241 | \qmlsignal PieSeries::startAngleChanged() |
242 | This signal is emitted when the pie start angle changes. |
243 | \sa startAngle |
244 | */ |
245 | |
246 | /*! |
247 | \property QPieSeries::endAngle |
248 | \brief The ending angle of the pie. |
249 | |
250 | A full pie is 360 degrees, where 0 degrees is at 12 o'clock. |
251 | |
252 | The default value is 360. |
253 | */ |
254 | |
255 | /*! |
256 | \qmlproperty real PieSeries::endAngle |
257 | |
258 | The ending angle of the pie. |
259 | |
260 | A full pie is 360 degrees, where 0 degrees is at 12 o'clock. |
261 | |
262 | The default value is 360. |
263 | */ |
264 | /*! |
265 | \qmlsignal PieSeries::endAngleChanged() |
266 | This signal is emitted when the pie end angle changes. |
267 | \sa endAngle |
268 | */ |
269 | |
270 | /*! |
271 | \property QPieSeries::count |
272 | |
273 | \brief The number of slices in the series. |
274 | */ |
275 | |
276 | /*! |
277 | \qmlproperty int PieSeries::count |
278 | |
279 | The number of slices in the series. |
280 | */ |
281 | |
282 | /*! |
283 | \qmlsignal PieSeries::countChanged() |
284 | This signal is emitted when the slice count changes. |
285 | \sa count |
286 | */ |
287 | |
288 | /*! |
289 | \property QPieSeries::sum |
290 | |
291 | \brief The sum of all slices. |
292 | |
293 | The series keeps track of the sum of all the slices it holds. |
294 | */ |
295 | |
296 | /*! |
297 | \qmlproperty real PieSeries::sum |
298 | |
299 | The sum of all slices. |
300 | |
301 | The series keeps track of the sum of all the slices it holds. |
302 | */ |
303 | |
304 | /*! |
305 | \qmlsignal PieSeries::sumChanged() |
306 | This signal is emitted when the sum of all slices changes. |
307 | \sa sum |
308 | */ |
309 | |
310 | /*! |
311 | \fn void QPieSeries::added(const QList<QPieSlice *> &slices) |
312 | |
313 | This signal is emitted when the slices specified by \a slices are added to the series. |
314 | |
315 | \sa append() |
316 | */ |
317 | /*! |
318 | \qmlsignal PieSeries::added(list<PieSlice> slices) |
319 | This signal is emitted when the slices specified by \a slices are added to the series. |
320 | */ |
321 | |
322 | /*! |
323 | \fn void QPieSeries::removed(const QList<QPieSlice *> &slices) |
324 | This signal is emitted when the slices specified by \a slices are removed from the series. |
325 | \sa remove() |
326 | */ |
327 | /*! |
328 | \qmlsignal PieSeries::removed(list<PieSlice> slices) |
329 | This signal is emitted when the slices specified by \a slices are removed from the series. |
330 | */ |
331 | |
332 | /*! |
333 | \qmlmethod PieSlice PieSeries::at(int index) |
334 | Returns the slice at the position specified by \a index. Returns null if the |
335 | index is not valid. |
336 | */ |
337 | |
338 | /*! |
339 | \qmlmethod PieSlice PieSeries::find(string label) |
340 | Returns the first slice that has the label \a label. Returns null if the label |
341 | is not found. |
342 | */ |
343 | |
344 | /*! |
345 | \qmlmethod PieSlice PieSeries::append(string label, real value) |
346 | Adds a new slice with the label \a label and the value \a value to the pie. |
347 | */ |
348 | |
349 | /*! |
350 | \qmlmethod bool PieSeries::remove(PieSlice slice) |
351 | Removes the slice specified by \a slice from the pie. Returns \c true if the |
352 | removal was successful, \c false otherwise. |
353 | */ |
354 | |
355 | /*! |
356 | \qmlmethod bool PieSeries::replace(int index, PieSlice slice) |
357 | Replaces the slice specified by \a slice from the pie at \a index. Returns \c true if the |
358 | replace was successful, \c false otherwise. |
359 | */ |
360 | |
361 | /*! |
362 | \qmlmethod PieSeries::clear() |
363 | Removes all slices from the pie. |
364 | */ |
365 | |
366 | /*! |
367 | \qmlmethod void PieSeries::removeMultiple(int index, int count) |
368 | Removes a range of slices as specified by the \a index and \a count. The call |
369 | traverses over all slices even if removal of one fails. |
370 | */ |
371 | |
372 | /*! |
373 | \qmlmethod bool PieSeries::remove(int index) |
374 | Removes the slice specified by \a index from the pie. Returns \c true if the |
375 | removal was successful, \c false otherwise. |
376 | */ |
377 | |
378 | /*! |
379 | \qmlmethod bool PieSeries::replace(PieSlice oldSlice, PieSlice newSlice) |
380 | Replaces the slice specified by \a oldSlice with newSlice. Returns \c true if the |
381 | removal was successful, \c false otherwise. \a oldSlice is destroyed if this |
382 | is successful. |
383 | */ |
384 | |
385 | /*! |
386 | \qmlmethod bool PieSeries::replace(list<PieSlice> slices) |
387 | Completely replaces all current slices with \a slices. The size does not need |
388 | to match. Returns false if any of the PieSlice in \a slices is invalid. |
389 | */ |
390 | |
391 | /*! |
392 | \qmlmethod bool PieSeries::take(PieSlice slice) |
393 | Takes a single slice, specified by \a slice, from the series. Does not delete |
394 | the slice object. Returns \c true if successful. |
395 | */ |
396 | |
397 | /*! |
398 | Constructs a series object that is a child of \a parent. |
399 | */ |
400 | QPieSeries::QPieSeries(QObject *parent) |
401 | : QAbstractSeries(*(new QPieSeriesPrivate()), parent) |
402 | {} |
403 | |
404 | QPieSeries::~QPieSeries() {} |
405 | |
406 | /*! |
407 | \reimp |
408 | |
409 | Returns the type of the series. |
410 | */ |
411 | QAbstractSeries::SeriesType QPieSeries::type() const |
412 | { |
413 | return QAbstractSeries::SeriesType::Pie; |
414 | } |
415 | |
416 | /*! |
417 | Returns the PieSlice at the position \a index. Returns null if no PieSlice was found. |
418 | */ |
419 | QPieSlice *QPieSeries::at(qsizetype index) |
420 | { |
421 | QList<QPieSlice *> sliceList = slices(); |
422 | if (index >= 0 && index < sliceList.size()) |
423 | return sliceList[index]; |
424 | |
425 | return 0; |
426 | } |
427 | |
428 | /*! |
429 | Searches for a PieSlice which contains the label \a label. Returns the PieSlice if found, null otherwise. |
430 | */ |
431 | QPieSlice *QPieSeries::find(const QString &label) |
432 | { |
433 | for (QPieSlice *slice : slices()) { |
434 | if (slice->label() == label) |
435 | return slice; |
436 | } |
437 | return 0; |
438 | } |
439 | |
440 | /*! |
441 | Replaces the PieSlice at position \a index with the one specified by \a slice. |
442 | The original PieSlice will be permanently deleted. Returns \c false if replacing |
443 | any of the PieSlices fails. |
444 | */ |
445 | bool QPieSeries::replace(qsizetype index, QPieSlice *slice) |
446 | { |
447 | Q_D(QPieSeries); |
448 | |
449 | if (index < 0) |
450 | index = 0; |
451 | if (!slice || d->m_slices.contains(t: slice)) |
452 | return false; |
453 | if (slice->series()) // already added to some series |
454 | return false; |
455 | if (qIsNaN(d: slice->value()) || qIsInf(d: slice->value())) |
456 | return false; |
457 | if (d->m_slices.size() <= index) |
458 | return false; |
459 | |
460 | emit removed(slices: QList<QPieSlice *>() << d->m_slices[index]); |
461 | delete d->m_slices[index]; |
462 | |
463 | slice->setParent(this); |
464 | slice->d_func()->m_series = this; |
465 | |
466 | d->m_slices[index] = slice; |
467 | |
468 | d->updateData(); |
469 | |
470 | QObject::connect(sender: slice, SIGNAL(sliceChanged()), receiver: this, SLOT(handleSliceChange())); |
471 | emit replaced(slices: QList<QPieSlice *>() << slice); |
472 | |
473 | return true; |
474 | } |
475 | |
476 | /*! |
477 | Removes multiple PieSlices from the series starting from \a index to a number of \a count. |
478 | The PieSlices will be permanently deleted. |
479 | */ |
480 | void QPieSeries::removeMultiple(qsizetype index, int count) |
481 | { |
482 | Q_D(QPieSeries); |
483 | |
484 | if (index + count >= d->m_slices.size()) |
485 | return; |
486 | if (index < 0 || count < 0) |
487 | return; |
488 | |
489 | QList<QPieSlice *> removedList; |
490 | |
491 | for (qsizetype i = index; i < index + count; ++i) { |
492 | auto slice = d->m_slices[index]; |
493 | d->m_slices.removeOne(t: slice); |
494 | d->updateData(); |
495 | |
496 | removedList << slice; |
497 | } |
498 | |
499 | emit removed(slices: removedList); |
500 | |
501 | for (auto slice : removedList) { |
502 | delete slice; |
503 | } |
504 | |
505 | emit countChanged(); |
506 | } |
507 | |
508 | /*! |
509 | Removes the PieSlice at the location \a index. The PieSlice will be permanently deleted. |
510 | Returns \c true if removing is successful. |
511 | */ |
512 | bool QPieSeries::remove(qsizetype index) |
513 | { |
514 | Q_D(QPieSeries); |
515 | |
516 | if (index >= d->m_slices.size()) |
517 | return false; |
518 | if (index < 0) |
519 | return false; |
520 | |
521 | return remove(slice: d->m_slices[index]); |
522 | } |
523 | |
524 | /*! |
525 | Replaces the PieSlice \a oldSlice with \a newSlice if found in the series.\a oldSlice will |
526 | be permanently deleted. Returns \c true if replacing is successful. |
527 | */ |
528 | bool QPieSeries::replace(QPieSlice *oldSlice, QPieSlice *newSlice) |
529 | { |
530 | Q_D(QPieSeries); |
531 | |
532 | if (!oldSlice || !newSlice) |
533 | return false; |
534 | if (oldSlice == newSlice) |
535 | return false; |
536 | if (d->m_slices.contains(t: newSlice)) |
537 | return false; |
538 | if (newSlice->series()) |
539 | return false; |
540 | if (qIsNaN(d: newSlice->value()) || qIsInf(d: newSlice->value())) |
541 | return false; |
542 | |
543 | for (int i = 0; i < d->m_slices.size(); ++i) { |
544 | if (d->m_slices[i] == oldSlice) { |
545 | emit removed(slices: QList<QPieSlice *>() << d->m_slices[i]); |
546 | delete d->m_slices[i]; |
547 | |
548 | newSlice->setParent(this); |
549 | newSlice->d_func()->m_series = this; |
550 | |
551 | d->m_slices[i] = newSlice; |
552 | |
553 | d->updateData(); |
554 | |
555 | QObject::connect(sender: newSlice, SIGNAL(sliceChanged()), receiver: this, SLOT(handleSliceChange())); |
556 | emit replaced(slices: QList<QPieSlice *>() << newSlice); |
557 | |
558 | return true; |
559 | } |
560 | } |
561 | |
562 | return false; |
563 | } |
564 | |
565 | /*! |
566 | Replaces the entire list of PieSlices in the series with the list specified by \a slices. |
567 | All the original PieSlices will be permanently deleted. Returns \c true if all PieSlices are |
568 | replaced successfully. |
569 | */ |
570 | bool QPieSeries::replace(const QList<QPieSlice *> &slices) |
571 | { |
572 | Q_D(QPieSeries); |
573 | |
574 | for (const auto slice : slices) { |
575 | if (!slice || d->m_slices.contains(t: slice)) |
576 | return false; |
577 | if (slice->series()) |
578 | return false; |
579 | if (qIsNaN(d: slice->value()) || qIsInf(d: slice->value())) |
580 | return false; |
581 | } |
582 | |
583 | emit removed(slices: d->m_slices); |
584 | for (auto &slice : d->m_slices) { |
585 | delete slice; |
586 | slice = nullptr; |
587 | } |
588 | |
589 | for (auto &slice : slices) { |
590 | slice->setParent(this); |
591 | slice->d_func()->m_series = this; |
592 | QObject::connect(sender: slice, SIGNAL(sliceChanged()), receiver: this, SLOT(handleSliceChange())); |
593 | } |
594 | |
595 | d->m_slices = slices; |
596 | emit replaced(slices); |
597 | |
598 | return true; |
599 | } |
600 | |
601 | /*! |
602 | Appends the slice specified by \a slice to the series. |
603 | Slice ownership is passed to the series. |
604 | |
605 | Returns \c true if appending succeeds. |
606 | */ |
607 | bool QPieSeries::append(QPieSlice *slice) |
608 | { |
609 | return append(slices: QList<QPieSlice *>() << slice); |
610 | } |
611 | |
612 | /*! |
613 | Appends the array of slices specified by \a slices to the series. |
614 | Slice ownership is passed to the series. |
615 | |
616 | Returns \c true if appending succeeds. |
617 | */ |
618 | bool QPieSeries::append(const QList<QPieSlice *> &slices) |
619 | { |
620 | Q_D(QPieSeries); |
621 | |
622 | if (slices.size() == 0) |
623 | return false; |
624 | |
625 | for (auto *s : slices) { |
626 | if (!s || d->m_slices.contains(t: s)) |
627 | return false; |
628 | if (s->series()) // already added to some series |
629 | return false; |
630 | if (qIsNaN(d: s->value()) || qIsInf(d: s->value())) |
631 | return false; |
632 | } |
633 | |
634 | for (auto *s : slices) { |
635 | s->setParent(this); |
636 | s->d_func()->m_series = this; |
637 | d->m_slices << s; |
638 | } |
639 | |
640 | d->updateData(); |
641 | |
642 | for (auto *s : slices) |
643 | QObject::connect(sender: s, SIGNAL(sliceChanged()), receiver: this, SLOT(handleSliceChange())); |
644 | |
645 | emit added(slices); |
646 | emit countChanged(); |
647 | |
648 | return true; |
649 | } |
650 | |
651 | /*! |
652 | Appends the slice specified by \a slice to the series and returns a reference to the series. |
653 | Slice ownership is passed to the series. |
654 | */ |
655 | QPieSeries &QPieSeries::operator << (QPieSlice *slice) |
656 | { |
657 | append(slice); |
658 | return *this; |
659 | } |
660 | |
661 | /*! |
662 | Appends a single slice with the specified \a value and \a label to the series. |
663 | Slice ownership is passed to the series. |
664 | Returns null if \a value is \c NaN, \c Inf, or \c -Inf and adds nothing to the |
665 | series. |
666 | */ |
667 | QPieSlice *QPieSeries::append(const QString &label, qreal value) |
668 | { |
669 | if (!(qIsNaN(d: value) || qIsInf(d: value))) { |
670 | QPieSlice *slice = new QPieSlice(label, value); |
671 | append(slice); |
672 | return slice; |
673 | } else { |
674 | return nullptr; |
675 | } |
676 | } |
677 | |
678 | /*! |
679 | Inserts the slice specified by \a slice to the series before the slice at |
680 | the position specified by \a index. |
681 | Slice ownership is passed to the series. |
682 | |
683 | Returns \c true if inserting succeeds. |
684 | */ |
685 | bool QPieSeries::insert(qsizetype index, QPieSlice *slice) |
686 | { |
687 | Q_D(QPieSeries); |
688 | |
689 | if (index < 0 || index > d->m_slices.size()) |
690 | return false; |
691 | |
692 | if (!slice || d->m_slices.contains(t: slice)) |
693 | return false; |
694 | |
695 | if (slice->series()) // already added to some series |
696 | return false; |
697 | |
698 | if (qIsNaN(d: slice->value()) || qIsInf(d: slice->value())) |
699 | return false; |
700 | |
701 | slice->setParent(this); |
702 | slice->d_func()->m_series = this; |
703 | d->m_slices.insert(i: index, t: slice); |
704 | |
705 | d->updateData(); |
706 | |
707 | connect(sender: slice, SIGNAL(sliceChanged()), receiver: this, SLOT(handleSliceChange())); |
708 | |
709 | emit added(slices: QList<QPieSlice *>() << slice); |
710 | emit countChanged(); |
711 | |
712 | return true; |
713 | } |
714 | |
715 | /*! |
716 | Removes a single slice, specified by \a slice, from the series and deletes it |
717 | permanently. |
718 | |
719 | The pointer cannot be referenced after this call. |
720 | |
721 | Returns \c true if the removal succeeds. |
722 | */ |
723 | bool QPieSeries::remove(QPieSlice *slice) |
724 | { |
725 | Q_D(QPieSeries); |
726 | |
727 | if (!d->m_slices.removeOne(t: slice)) |
728 | return false; |
729 | |
730 | d->updateData(); |
731 | |
732 | emit removed(slices: QList<QPieSlice *>() << slice); |
733 | emit countChanged(); |
734 | |
735 | delete slice; |
736 | slice = 0; |
737 | |
738 | return true; |
739 | } |
740 | |
741 | /*! |
742 | Takes a single slice, specified by \a slice, from the series. Does not delete |
743 | the slice object. |
744 | |
745 | \note The series remains the slice's parent object. You must set the |
746 | parent object to take full ownership. |
747 | |
748 | Returns \c true if the take operation was successful. |
749 | */ |
750 | bool QPieSeries::take(QPieSlice *slice) |
751 | { |
752 | Q_D(QPieSeries); |
753 | |
754 | if (!d->m_slices.removeOne(t: slice)) |
755 | return false; |
756 | |
757 | slice->d_func()->m_series = 0; |
758 | slice->disconnect(receiver: this); |
759 | |
760 | d->updateData(); |
761 | |
762 | emit removed(slices: QList<QPieSlice *>() << slice); |
763 | emit countChanged(); |
764 | |
765 | return true; |
766 | } |
767 | |
768 | /*! |
769 | Clears all slices from the series. |
770 | */ |
771 | void QPieSeries::clear() |
772 | { |
773 | Q_D(QPieSeries); |
774 | if (d->m_slices.size() == 0) |
775 | return; |
776 | |
777 | QList<QPieSlice *> slices = d->m_slices; |
778 | for (QPieSlice *s : d->m_slices) |
779 | d->m_slices.removeOne(t: s); |
780 | |
781 | d->updateData(); |
782 | |
783 | emit removed(slices); |
784 | emit countChanged(); |
785 | |
786 | for (QPieSlice *s : slices) |
787 | delete s; |
788 | } |
789 | |
790 | /*! |
791 | Returns a list of slices that belong to this series. |
792 | */ |
793 | QList<QPieSlice *> QPieSeries::slices() const |
794 | { |
795 | Q_D(const QPieSeries); |
796 | return d->m_slices; |
797 | } |
798 | |
799 | /*! |
800 | Returns the number of the slices in this series. |
801 | */ |
802 | qsizetype QPieSeries::count() const |
803 | { |
804 | Q_D(const QPieSeries); |
805 | return d->m_slices.size(); |
806 | } |
807 | |
808 | /*! |
809 | Returns \c true if the series is empty. |
810 | */ |
811 | bool QPieSeries::isEmpty() const |
812 | { |
813 | Q_D(const QPieSeries); |
814 | return d->m_slices.isEmpty(); |
815 | } |
816 | |
817 | /*! |
818 | Returns the sum of all slice values in this series. |
819 | |
820 | \sa QPieSlice::value(), QPieSlice::setValue(), QPieSlice::percentage() |
821 | */ |
822 | qreal QPieSeries::sum() const |
823 | { |
824 | Q_D(const QPieSeries); |
825 | return d->m_sum; |
826 | } |
827 | |
828 | void QPieSeries::setHorizontalPosition(qreal relativePosition) |
829 | { |
830 | Q_D(QPieSeries); |
831 | |
832 | if (relativePosition < 0.0) |
833 | relativePosition = 0.0; |
834 | if (relativePosition > 1.0) |
835 | relativePosition = 1.0; |
836 | |
837 | if (qFuzzyCompare(p1: d->m_pieRelativeHorPos, p2: relativePosition)) |
838 | return; |
839 | |
840 | d->m_pieRelativeHorPos = relativePosition; |
841 | emit horizontalPositionChanged(); |
842 | emit update(); |
843 | } |
844 | |
845 | qreal QPieSeries::horizontalPosition() const |
846 | { |
847 | Q_D(const QPieSeries); |
848 | return d->m_pieRelativeHorPos; |
849 | } |
850 | |
851 | void QPieSeries::setVerticalPosition(qreal relativePosition) |
852 | { |
853 | Q_D(QPieSeries); |
854 | |
855 | if (relativePosition < 0.0) |
856 | relativePosition = 0.0; |
857 | if (relativePosition > 1.0) |
858 | relativePosition = 1.0; |
859 | |
860 | if (qFuzzyCompare(p1: d->m_pieRelativeVerPos, p2: relativePosition)) |
861 | return; |
862 | |
863 | d->m_pieRelativeVerPos = relativePosition; |
864 | emit verticalPositionChanged(); |
865 | emit update(); |
866 | } |
867 | |
868 | qreal QPieSeries::verticalPosition() const |
869 | { |
870 | Q_D(const QPieSeries); |
871 | return d->m_pieRelativeVerPos; |
872 | } |
873 | |
874 | void QPieSeries::setPieSize(qreal relativeSize) |
875 | { |
876 | Q_D(QPieSeries); |
877 | relativeSize = qBound(min: (qreal)0.0, val: relativeSize, max: (qreal)1.0); |
878 | d->setSizes(innerSize: qMin(a: d->m_holeRelativeSize, b: relativeSize), outerSize: relativeSize); |
879 | } |
880 | |
881 | qreal QPieSeries::pieSize() const |
882 | { |
883 | Q_D(const QPieSeries); |
884 | return d->m_pieRelativeSize; |
885 | } |
886 | |
887 | /*! |
888 | Sets the start angle of the pie. |
889 | |
890 | A full pie is 360 degrees, where 0 degrees is at 12 o'clock. |
891 | |
892 | \a angle must be smaller than the end angle. |
893 | |
894 | \sa startAngle(), endAngle(), setEndAngle() |
895 | */ |
896 | void QPieSeries::setStartAngle(qreal angle) |
897 | { |
898 | Q_D(QPieSeries); |
899 | if (qFuzzyCompare(p1: d->m_pieStartAngle, p2: angle)) |
900 | return; |
901 | d->m_pieStartAngle = angle; |
902 | d->updateData(); |
903 | emit startAngleChanged(); |
904 | emit update(); |
905 | } |
906 | |
907 | /*! |
908 | Returns the start angle of the pie. |
909 | |
910 | A full pie is 360 degrees, where 0 degrees is at 12 o'clock. |
911 | |
912 | \sa setStartAngle(), endAngle(), setEndAngle() |
913 | */ |
914 | qreal QPieSeries::startAngle() const |
915 | { |
916 | Q_D(const QPieSeries); |
917 | return d->m_pieStartAngle; |
918 | } |
919 | |
920 | /*! |
921 | Sets the end angle of the pie. |
922 | |
923 | A full pie is 360 degrees, where 0 degrees is at 12 o'clock. |
924 | |
925 | \a angle must be greater than the start angle. |
926 | |
927 | \sa endAngle(), startAngle(), setStartAngle() |
928 | */ |
929 | void QPieSeries::setEndAngle(qreal angle) |
930 | { |
931 | Q_D(QPieSeries); |
932 | if (qFuzzyCompare(p1: d->m_pieEndAngle, p2: angle)) |
933 | return; |
934 | d->m_pieEndAngle = angle; |
935 | d->updateData(); |
936 | emit endAngleChanged(); |
937 | emit update(); |
938 | } |
939 | |
940 | /*! |
941 | Returns the end angle of the pie. |
942 | |
943 | A full pie is 360 degrees, where 0 degrees is at 12 o'clock. |
944 | |
945 | \sa setEndAngle(), startAngle(), setStartAngle() |
946 | */ |
947 | qreal QPieSeries::endAngle() const |
948 | { |
949 | Q_D(const QPieSeries); |
950 | return d->m_pieEndAngle; |
951 | } |
952 | |
953 | void QPieSeries::componentComplete() |
954 | { |
955 | for (QObject *child : children()) { |
956 | if (qobject_cast<QPieSlice *>(object: child)) |
957 | QPieSeries::append(slice: qobject_cast<QPieSlice *>(object: child)); |
958 | } |
959 | QAbstractSeries::componentComplete(); |
960 | } |
961 | |
962 | /*! |
963 | Sets the visibility of all slice labels to \a visible. |
964 | |
965 | \note This function affects only the current slices in the series. |
966 | If a new slice is added, the default label visibility is \c false. |
967 | |
968 | \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible() |
969 | */ |
970 | void QPieSeries::setLabelsVisible(bool visible) |
971 | { |
972 | Q_D(QPieSeries); |
973 | for (QPieSlice *s : d->m_slices) |
974 | s->setLabelVisible(visible); |
975 | } |
976 | |
977 | /*! |
978 | Sets the position of all the slice labels to \a position. |
979 | |
980 | \note This function affects only the current slices in the series. |
981 | If a new slice is added, the default label position is QPieSlice::LabelOutside. |
982 | |
983 | \sa QPieSlice::labelPosition(), QPieSlice::setLabelPosition() |
984 | */ |
985 | void QPieSeries::setLabelsPosition(QPieSlice::LabelPosition position) |
986 | { |
987 | Q_D(QPieSeries); |
988 | for (QPieSlice *s : d->m_slices) |
989 | s->setLabelPosition(position); |
990 | } |
991 | |
992 | void QPieSeries::handleSliceChange() |
993 | { |
994 | QPieSlice *pSlice = qobject_cast<QPieSlice *>(object: sender()); |
995 | Q_D(QPieSeries); |
996 | Q_ASSERT(d->m_slices.contains(pSlice)); |
997 | d->updateData(); |
998 | } |
999 | |
1000 | QPieSeries::QPieSeries(QPieSeriesPrivate &dd, QObject *parent) |
1001 | : QAbstractSeries(dd, parent) |
1002 | {} |
1003 | |
1004 | void QPieSeries::setHoleSize(qreal holeSize) |
1005 | { |
1006 | Q_D(QPieSeries); |
1007 | holeSize = qBound(min: (qreal)0.0, val: holeSize, max: (qreal)1.0); |
1008 | d->setSizes(innerSize: holeSize, outerSize: qMax(a: d->m_pieRelativeSize, b: holeSize)); |
1009 | } |
1010 | |
1011 | qreal QPieSeries::holeSize() const |
1012 | { |
1013 | Q_D(const QPieSeries); |
1014 | return d->m_holeRelativeSize; |
1015 | } |
1016 | |
1017 | QPieSeriesPrivate::QPieSeriesPrivate() |
1018 | : m_pieRelativeHorPos(.5) |
1019 | , m_pieRelativeVerPos(.5) |
1020 | , m_pieRelativeSize(.7) |
1021 | , m_pieStartAngle(0) |
1022 | , m_pieEndAngle(360) |
1023 | , m_sum(0) |
1024 | , m_holeRelativeSize(.0) |
1025 | {} |
1026 | |
1027 | void QPieSeriesPrivate::updateData() |
1028 | { |
1029 | Q_Q(QPieSeries); |
1030 | |
1031 | // calculate sum of all slices |
1032 | qreal sum = 0; |
1033 | for (QPieSlice *s : m_slices) |
1034 | sum += s->value(); |
1035 | |
1036 | if (!qFuzzyCompare(p1: m_sum, p2: sum)) { |
1037 | m_sum = sum; |
1038 | emit q->sumChanged(); |
1039 | } |
1040 | |
1041 | // nothing to show.. |
1042 | if (qFuzzyCompare(p1: m_sum, p2: 0)) |
1043 | return; |
1044 | |
1045 | // update slice attributes |
1046 | qreal sliceAngle = m_pieStartAngle; |
1047 | qreal pieSpan = m_pieEndAngle - m_pieStartAngle; |
1048 | for (QPieSlice *s : m_slices) { |
1049 | QPieSlicePrivate *d = s->d_func(); |
1050 | d->setPercentage(s->value() / m_sum); |
1051 | d->setStartAngle(sliceAngle); |
1052 | d->setAngleSpan(pieSpan * s->percentage()); |
1053 | sliceAngle += s->angleSpan(); |
1054 | } |
1055 | |
1056 | emit q->update(); |
1057 | } |
1058 | |
1059 | void QPieSeriesPrivate::updateLabels() |
1060 | { |
1061 | Q_Q(QPieSeries); |
1062 | |
1063 | emit q->update(); |
1064 | } |
1065 | |
1066 | void QPieSeriesPrivate::setSizes(qreal innerSize, qreal outerSize) |
1067 | { |
1068 | Q_Q(QPieSeries); |
1069 | if (!qFuzzyCompare(p1: m_holeRelativeSize, p2: innerSize)) { |
1070 | m_holeRelativeSize = innerSize; |
1071 | emit q->holeSizeChanged(); |
1072 | } |
1073 | |
1074 | if (!qFuzzyCompare(p1: m_pieRelativeSize, p2: outerSize)) { |
1075 | m_pieRelativeSize = outerSize; |
1076 | emit q->pieSizeChanged(); |
1077 | } |
1078 | } |
1079 | |
1080 | QT_END_NAMESPACE |
1081 |
Definitions
- QPieSeries
- ~QPieSeries
- type
- at
- find
- replace
- removeMultiple
- remove
- replace
- replace
- append
- append
- operator <<
- append
- insert
- remove
- take
- clear
- slices
- count
- isEmpty
- sum
- setHorizontalPosition
- horizontalPosition
- setVerticalPosition
- verticalPosition
- setPieSize
- pieSize
- setStartAngle
- startAngle
- setEndAngle
- endAngle
- componentComplete
- setLabelsVisible
- setLabelsPosition
- handleSliceChange
- QPieSeries
- setHoleSize
- holeSize
- QPieSeriesPrivate
- updateData
- updateLabels
Start learning QML with our Intro Training
Find out more