##// END OF EJS Templates
Use signals from pieseries, visible hover and exploding slices
Jani Honkonen -
r157:036a0ec8efe0
parent child
Show More
@@ -17,10 +17,10 int main(int argc, char *argv[])
17 17 Q_ASSERT(series);
18 18
19 19 // Add test data to the series
20 series->add(QPieSlice(1, "test1", Qt::red));
20 series->add(QPieSlice(1, "test1", Qt::red, true));
21 21 series->add(QPieSlice(2, "test2", Qt::green));
22 22 series->add(QPieSlice(3, "test3", Qt::blue));
23 series->add(QPieSlice(4, "test4", Qt::darkRed));
23 series->add(QPieSlice(4, "test4", Qt::darkRed, true));
24 24 series->add(QPieSlice(5, "test5", Qt::darkGreen));
25 25
26 26 // Use the chart widget as the central widget
@@ -147,7 +147,7 void ChartPresenter::handleSeriesAdded(QChartSeries* series)
147 147 case QChartSeries::SeriesTypePie: {
148 148 QPieSeries *pieSeries = qobject_cast<QPieSeries *>(series);
149 149 PiePresenter* pie = new PiePresenter(m_chart, pieSeries);
150 pieSeries->m_piePresenter = pie; // TODO: remove this pointer passing use signals&slots
150 QObject::connect(pieSeries, SIGNAL(changed(const PieChangeSet&)), pie, SLOT(handleSeriesChanged(const PieChangeSet&)));
151 151 QObject::connect(this, SIGNAL(geometryChanged(const QRectF&)), pie, SLOT(handleGeometryChanged(const QRectF&)));
152 152 QObject::connect(m_dataset, SIGNAL(domainChanged(const Domain&)), pie, SLOT(handleDomainChanged(const Domain&)));
153 153 m_chartItems.insert(series, pie);
@@ -21,7 +21,7 PiePresenter::~PiePresenter()
21 21 delete m_slices.takeLast();
22 22 }
23 23
24 void PiePresenter::seriesChanged()
24 void PiePresenter::handleSeriesChanged(const PieChangeSet& changeSet)
25 25 {
26 26 const qreal fullPie = 360;
27 27 qreal total = 0;
@@ -43,25 +43,25 void PiePresenter::seriesChanged()
43 43 m_slices.append(slice);
44 44 angle += span;
45 45 }
46
47 resize();
48 46 }
49 47
50 void PiePresenter::resize()
48 void PiePresenter::updateGeometry()
51 49 {
50 prepareGeometryChange();
51
52 52 m_pieRect = m_rect;
53 53
54 54 if (m_pieRect.width() < m_pieRect.height()) {
55 m_pieRect.setWidth(m_pieRect.width() * m_pieSeries->m_sizeFactor);
55 m_pieRect.setWidth(m_pieRect.width() * m_pieSeries->sizeFactor());
56 56 m_pieRect.setHeight(m_pieRect.width());
57 57 m_pieRect.moveCenter(m_rect.center());
58 58 } else {
59 m_pieRect.setHeight(m_pieRect.height() * m_pieSeries->m_sizeFactor);
59 m_pieRect.setHeight(m_pieRect.height() * m_pieSeries->sizeFactor());
60 60 m_pieRect.setWidth(m_pieRect.height());
61 61 m_pieRect.moveCenter(m_rect.center());
62 62 }
63 63
64 switch (m_pieSeries->m_position) {
64 switch (m_pieSeries->position()) {
65 65 case QPieSeries::PiePositionTopLeft: {
66 66 m_pieRect.setHeight(m_pieRect.height() / 2);
67 67 m_pieRect.setWidth(m_pieRect.height());
@@ -92,6 +92,8 void PiePresenter::resize()
92 92
93 93 qDebug() << "presentation rect:" << m_rect;
94 94 qDebug() << "pie rect:" << m_pieRect;
95 foreach (PieSlice *slice, m_slices)
96 slice->updateGeometry();
95 97 }
96 98
97 99 void PiePresenter::handleDomainChanged(const Domain& domain)
@@ -101,10 +103,9 void PiePresenter::handleDomainChanged(const Domain& domain)
101 103
102 104 void PiePresenter::handleGeometryChanged(const QRectF& rect)
103 105 {
104 // TODO: allow user setting the size?
105 // TODO: allow user defining the margins?
106 m_rect.setSize(rect.size());
107 resize();
106 m_rect = rect;
107 updateGeometry();
108
108 109 }
109 110
110 111 #include "moc_piepresenter.cpp"
@@ -17,16 +17,16 public:
17 17 PiePresenter(QGraphicsItem *parent, QPieSeries *series);
18 18 ~PiePresenter();
19 19
20 public: // from ChartItem
20 public: // from QGraphicsItem
21 21 QRectF boundingRect() const { return m_rect; }
22 22 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {}
23 23
24 24 public:
25 void seriesChanged();
26 void resize();
25 void updateGeometry();
27 26 QRectF pieRect() const { return m_pieRect; }
28 27
29 28 public Q_SLOTS:
29 void handleSeriesChanged(const PieChangeSet& changeSet);
30 30 void handleDomainChanged(const Domain& domain);
31 31 void handleGeometryChanged(const QRectF& rect);
32 32
@@ -1,19 +1,37
1 1 #include "pieslice.h"
2 2 #include "piepresenter.h"
3 #include "qpieseries.h"
3 4 #include <QPainter>
4 5 #include <QDebug>
6 #include <qmath.h>
5 7
6 8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
7 9
8 PieSlice::PieSlice(PiePresenter *piePresentation, int seriesIndex, qreal startAngle, qreal span)
9 :QGraphicsItem(piePresentation),
10 #define PI 3.14159265
11 #define EXPLODE_OFFSET 20
12
13 QPointF offset(qreal angle, qreal length)
14 {
15 qreal dx = qSin(angle*(PI/180)) * length;
16 qreal dy = qCos(angle*(PI/180)) * length;
17 return QPointF(dx, -dy);
18 }
19
20 PieSlice::PieSlice(PiePresenter *presenter, int seriesIndex, qreal startAngle, qreal span)
21 :QGraphicsItem(presenter),
22 m_label(new QGraphicsTextItem(this)),
10 23 m_seriesIndex(seriesIndex),
11 24 m_startAngle(startAngle),
12 25 m_span(span)
13 26 {
14 Q_ASSERT(piePresentation);
27 Q_ASSERT(presenter);
15 28 setAcceptHoverEvents(true);
16 29 setAcceptedMouseButtons(Qt::LeftButton);
30 updateGeometry();
31
32 // TODO: use themes
33 m_pen = QPen(Qt::black);
34 m_brush = QBrush(sliceData().m_color);
17 35 }
18 36
19 37 PieSlice::~PieSlice()
@@ -22,70 +40,85 PieSlice::~PieSlice()
22 40
23 41 QRectF PieSlice::boundingRect() const
24 42 {
25 return shape().boundingRect();
43 return m_rect;
26 44 }
27 45
28 46 QPainterPath PieSlice::shape() const
29 47 {
30 QRectF rect = (static_cast<PiePresenter*>(parentItem()))->pieRect();
31 qreal angle = (-m_startAngle) + (90);
32 qreal span = -m_span;
33
34 QPainterPath path;
35 path.moveTo(rect.center());
36 path.arcTo(rect, angle, span);
37
38 // TODO: draw the shape so that it might have a hole in the center
39 // - Sin & Cos will be needed to find inner/outer arc endpoints
40
41 // dx, dy are offsets from the center
42 //qreal l = boundingRect().height();
43 //qreal dx = qSin(angle*(M_PI/180)) * l;
44 //qreal dy = qCos(angle*(M_PI/180)) * l;
45
46 // TODO: exploded slice?
47
48 return path;
48 return m_path;
49 49 }
50 50
51 51 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
52 52 {
53 53 painter->setRenderHint(QPainter::Antialiasing);
54 // TODO: how to map theme settings to a pie slice? Now we
55 //painter->setPen(m_theme.linePen);
56 // TODO:
57
58 QPieSlice data = (static_cast<PiePresenter*>(parentItem()))->m_pieSeries->slice(m_seriesIndex);
59 painter->setBrush(data.m_color);
60 54
61
62 //painter->setBrush(m_theme.linePen.color());
63
64 // From Qt docs:
65 // The startAngle and spanAngle must be specified in 1/16th of a degree, i.e. a full circle equals 5760 (16 * 360).
66 // Positive values for the angles mean counter-clockwise while negative values mean the clockwise direction.
67 // Zero degrees is at the 3 o'clock position.
68 //
69 // For sake of simplicity convert this so that zero degrees is at 12 o'clock and full circle is 360.
70 //qreal angle = (-m_startAngle*16) + (90*16);
71 //qreal span = -m_span*16;
72 //painter->drawPie(boundingRect(), angle, span);
73
74 painter->drawPath(shape());
55 // TODO: themes
56 painter->setPen(m_pen);
57 painter->setBrush(m_brush);
58 painter->drawPath(m_path);
75 59
76 60 // Draw the label
77 61 // TODO: do this better
78 painter->drawText(boundingRect().center(), data.m_label);
62 //QTextItem text;
63 painter->drawText(m_center, sliceData().m_label);
79 64 }
80 65
81 66 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent * event)
82 67 {
83 68 QGraphicsItem::hoverEnterEvent(event);
84 qDebug() << "hover" << m_seriesIndex << m_startAngle << m_span;
69 m_brush = QBrush(sliceData().m_color.lighter());
70 update();
71 }
72
73 void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent * event)
74 {
75 QGraphicsItem::hoverLeaveEvent(event);
76 m_brush = QBrush(sliceData().m_color);
77 update();
85 78 }
86 79
87 80 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent *event)
88 81 {
89 82 QGraphicsItem::mousePressEvent(event);
83 QPieSlice data = sliceData();
84 data.m_isExploded = !data.m_isExploded;
85 (static_cast<PiePresenter*>(parentItem()))->m_pieSeries->update(m_seriesIndex, data);
86 }
87
88 void PieSlice::updateGeometry()
89 {
90 prepareGeometryChange();
91
92 PiePresenter *presenter = static_cast<PiePresenter*>(parentItem());
93 QRectF rect = presenter->pieRect();
94 rect.adjust(EXPLODE_OFFSET, EXPLODE_OFFSET, -EXPLODE_OFFSET ,-EXPLODE_OFFSET);
95
96 qreal centerAngle = m_startAngle + (m_span/2);
97
98 if (presenter->m_pieSeries->slice(m_seriesIndex).m_isExploded) {
99 QPointF d = offset((centerAngle), EXPLODE_OFFSET);
100 rect.translate(d.x(), d.y());
101 }
102
103 qreal angle = (-m_startAngle) + (90);
104 qreal span = -m_span;
105
106 QPainterPath path;
107 path.moveTo(rect.center());
108 path.arcTo(rect, angle, span);
109
110 // TODO: draw the shape so that it might have a hole in the center
111
112 m_path = path;
113 m_rect = path.boundingRect();
114
115 qreal radius = rect.height() / 2;
116 m_center = rect.center() + offset(centerAngle, radius / 2);
90 117 }
118
119 QPieSlice PieSlice::sliceData()
120 {
121 return (static_cast<PiePresenter*>(parentItem()))->m_pieSeries->slice(m_seriesIndex);
122 }
123
91 124 QTCOMMERCIALCHART_END_NAMESPACE
@@ -3,9 +3,11
3 3
4 4 #include "qchartglobal.h"
5 5 #include "charttheme_p.h"
6 #include "qpieseries.h"
6 7 #include <QGraphicsItem>
7 8 #include <QRectF>
8 9 #include <QColor>
10 #include <QPen>
9 11
10 12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11 13 class PiePresenter;
@@ -13,7 +15,7 class PiePresenter;
13 15 class PieSlice : public QGraphicsItem
14 16 {
15 17 public:
16 PieSlice(PiePresenter *piePresentation, int seriesIndex, qreal startAngle, qreal span);
18 PieSlice(PiePresenter *piePresenter, int seriesIndex, qreal startAngle, qreal span);
17 19 ~PieSlice();
18 20
19 21 public: // from QGraphicsItem
@@ -21,14 +23,25 public: // from QGraphicsItem
21 23 QPainterPath shape() const;
22 24 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
23 25 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
26 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
24 27 void mousePressEvent(QGraphicsSceneMouseEvent *event);
25 28
29 public:
30 void updateGeometry();
31
32 private:
33 QPieSlice sliceData();
34
26 35 private:
36 QGraphicsTextItem* m_label;
27 37 int m_seriesIndex;
28 38 qreal m_startAngle;
29 39 qreal m_span;
40 QPainterPath m_path;
30 41 QRectF m_rect;
31 //SeriesTheme m_theme;
42 QPointF m_center;
43 QPen m_pen;
44 QBrush m_brush;
32 45 };
33 46
34 47 QTCOMMERCIALCHART_END_NAMESPACE
@@ -7,7 +7,6 QTCOMMERCIALCHART_BEGIN_NAMESPACE
7 7
8 8 QPieSeries::QPieSeries(QObject *parent) :
9 9 QChartSeries(parent),
10 m_piePresenter(0),
11 10 m_sizeFactor(1.0),
12 11 m_position(PiePositionMaximized)
13 12 {
@@ -20,21 +19,30 QPieSeries::~QPieSeries()
20 19
21 20 void QPieSeries::set(QList<QPieSlice> slices)
22 21 {
23 m_slices = slices;
24 if (m_piePresenter) {
25 m_piePresenter->seriesChanged();
26 m_piePresenter->update();
22 PieChangeSet changeSet;
23
24 for (int i=slices.count(); i<m_slices.count(); i++)
25 changeSet.m_removed << i;
26
27 for (int i=0; i<slices.count(); i++) {
28 if (i < m_slices.count())
29 changeSet.m_changed << i;
30 else
31 changeSet.m_added << i;
27 32 }
33
34 m_slices = slices;
35 emit changed(changeSet);
28 36 }
29 37
30 38 void QPieSeries::add(QList<QPieSlice> slices)
31 39 {
40 PieChangeSet changeSet;
41 for (int i=0; i<slices.count(); i++)
42 changeSet.m_added << m_slices.count() + i;
43
32 44 m_slices += slices;
33 if (m_piePresenter) {
34 m_piePresenter->seriesChanged();
35 // TODO: m_piePresenter->seriesAppended()??
36 m_piePresenter->update();
37 }
45 emit changed(changeSet);
38 46 }
39 47
40 48 void QPieSeries::add(QPieSlice slice)
@@ -53,12 +61,9 bool QPieSeries::update(int index, QPieSlice slice)
53 61 {
54 62 if ((index >= 0) && (index < m_slices.count())) {
55 63 m_slices[index] = slice;
56 if (m_piePresenter) {
57 m_piePresenter->seriesChanged();
58 // TODO: for a nice animation we need something like
59 // m_piePresenter->sliceChanged(index, oldslice, newslice)
60 m_piePresenter->update();
61 }
64 PieChangeSet changeSet;
65 changeSet.m_changed << index;
66 emit changed(changeSet);
62 67 return true;
63 68 }
64 69 return false;
@@ -68,24 +73,13 void QPieSeries::setSizeFactor(qreal factor)
68 73 {
69 74 if (factor > 0.0)
70 75 m_sizeFactor = factor;
71
72 if (m_piePresenter) {
73 m_piePresenter->resize();
74 m_piePresenter->update();
75 // TODO: do we have to update the parent item also?
76 // - potential issue: what if this function is called from the parent context?
77 }
76 emit sizeFactorChanged();
78 77 }
79 78
80 79 void QPieSeries::setPosition(PiePosition position)
81 80 {
82 81 m_position = position;
83 if (m_piePresenter) {
84 m_piePresenter->resize();
85 m_piePresenter->update();
86 // TODO: do we have to update the parent item also?
87 // - potential issue: what if this function is called from the parent context?
88 }
82 emit positionChanged();
89 83 }
90 84
91 85 #include "moc_qpieseries.cpp"
@@ -26,6 +26,14 public:
26 26 bool m_isExploded;
27 27 };
28 28
29 class PieChangeSet
30 {
31 public:
32 QList<int> m_added;
33 QList<int> m_removed;
34 QList<int> m_changed;
35 };
36
29 37 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QChartSeries
30 38 {
31 39 Q_OBJECT
@@ -69,13 +77,14 public:
69 77 void setPosition(PiePosition position);
70 78 PiePosition position() const { return m_position; }
71 79
80 Q_SIGNALS:
81 void changed(const PieChangeSet& changeSet);
82 void sizeFactorChanged();
83 void positionChanged();
84
72 85 private:
73 86 Q_DISABLE_COPY(QPieSeries)
74 87 // TODO: use PIML
75 friend class ChartPresenter;
76 friend class ChartDataSet;
77 friend class PiePresenter;
78 PiePresenter *m_piePresenter;
79 88 QList<QPieSlice> m_slices;
80 89 qreal m_sizeFactor;
81 90 PiePosition m_position;
General Comments 0
You need to be logged in to leave comments. Login now