##// 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 Q_ASSERT(series);
17 Q_ASSERT(series);
18
18
19 // Add test data to the series
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 series->add(QPieSlice(2, "test2", Qt::green));
21 series->add(QPieSlice(2, "test2", Qt::green));
22 series->add(QPieSlice(3, "test3", Qt::blue));
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 series->add(QPieSlice(5, "test5", Qt::darkGreen));
24 series->add(QPieSlice(5, "test5", Qt::darkGreen));
25
25
26 // Use the chart widget as the central widget
26 // Use the chart widget as the central widget
@@ -147,7 +147,7 void ChartPresenter::handleSeriesAdded(QChartSeries* series)
147 case QChartSeries::SeriesTypePie: {
147 case QChartSeries::SeriesTypePie: {
148 QPieSeries *pieSeries = qobject_cast<QPieSeries *>(series);
148 QPieSeries *pieSeries = qobject_cast<QPieSeries *>(series);
149 PiePresenter* pie = new PiePresenter(m_chart, pieSeries);
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 QObject::connect(this, SIGNAL(geometryChanged(const QRectF&)), pie, SLOT(handleGeometryChanged(const QRectF&)));
151 QObject::connect(this, SIGNAL(geometryChanged(const QRectF&)), pie, SLOT(handleGeometryChanged(const QRectF&)));
152 QObject::connect(m_dataset, SIGNAL(domainChanged(const Domain&)), pie, SLOT(handleDomainChanged(const Domain&)));
152 QObject::connect(m_dataset, SIGNAL(domainChanged(const Domain&)), pie, SLOT(handleDomainChanged(const Domain&)));
153 m_chartItems.insert(series, pie);
153 m_chartItems.insert(series, pie);
@@ -21,7 +21,7 PiePresenter::~PiePresenter()
21 delete m_slices.takeLast();
21 delete m_slices.takeLast();
22 }
22 }
23
23
24 void PiePresenter::seriesChanged()
24 void PiePresenter::handleSeriesChanged(const PieChangeSet& changeSet)
25 {
25 {
26 const qreal fullPie = 360;
26 const qreal fullPie = 360;
27 qreal total = 0;
27 qreal total = 0;
@@ -43,25 +43,25 void PiePresenter::seriesChanged()
43 m_slices.append(slice);
43 m_slices.append(slice);
44 angle += span;
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 m_pieRect = m_rect;
52 m_pieRect = m_rect;
53
53
54 if (m_pieRect.width() < m_pieRect.height()) {
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 m_pieRect.setHeight(m_pieRect.width());
56 m_pieRect.setHeight(m_pieRect.width());
57 m_pieRect.moveCenter(m_rect.center());
57 m_pieRect.moveCenter(m_rect.center());
58 } else {
58 } else {
59 m_pieRect.setHeight(m_pieRect.height() * m_pieSeries->m_sizeFactor);
59 m_pieRect.setHeight(m_pieRect.height() * m_pieSeries->sizeFactor());
60 m_pieRect.setWidth(m_pieRect.height());
60 m_pieRect.setWidth(m_pieRect.height());
61 m_pieRect.moveCenter(m_rect.center());
61 m_pieRect.moveCenter(m_rect.center());
62 }
62 }
63
63
64 switch (m_pieSeries->m_position) {
64 switch (m_pieSeries->position()) {
65 case QPieSeries::PiePositionTopLeft: {
65 case QPieSeries::PiePositionTopLeft: {
66 m_pieRect.setHeight(m_pieRect.height() / 2);
66 m_pieRect.setHeight(m_pieRect.height() / 2);
67 m_pieRect.setWidth(m_pieRect.height());
67 m_pieRect.setWidth(m_pieRect.height());
@@ -92,6 +92,8 void PiePresenter::resize()
92
92
93 qDebug() << "presentation rect:" << m_rect;
93 qDebug() << "presentation rect:" << m_rect;
94 qDebug() << "pie rect:" << m_pieRect;
94 qDebug() << "pie rect:" << m_pieRect;
95 foreach (PieSlice *slice, m_slices)
96 slice->updateGeometry();
95 }
97 }
96
98
97 void PiePresenter::handleDomainChanged(const Domain& domain)
99 void PiePresenter::handleDomainChanged(const Domain& domain)
@@ -101,10 +103,9 void PiePresenter::handleDomainChanged(const Domain& domain)
101
103
102 void PiePresenter::handleGeometryChanged(const QRectF& rect)
104 void PiePresenter::handleGeometryChanged(const QRectF& rect)
103 {
105 {
104 // TODO: allow user setting the size?
106 m_rect = rect;
105 // TODO: allow user defining the margins?
107 updateGeometry();
106 m_rect.setSize(rect.size());
108
107 resize();
108 }
109 }
109
110
110 #include "moc_piepresenter.cpp"
111 #include "moc_piepresenter.cpp"
@@ -17,16 +17,16 public:
17 PiePresenter(QGraphicsItem *parent, QPieSeries *series);
17 PiePresenter(QGraphicsItem *parent, QPieSeries *series);
18 ~PiePresenter();
18 ~PiePresenter();
19
19
20 public: // from ChartItem
20 public: // from QGraphicsItem
21 QRectF boundingRect() const { return m_rect; }
21 QRectF boundingRect() const { return m_rect; }
22 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {}
22 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {}
23
23
24 public:
24 public:
25 void seriesChanged();
25 void updateGeometry();
26 void resize();
27 QRectF pieRect() const { return m_pieRect; }
26 QRectF pieRect() const { return m_pieRect; }
28
27
29 public Q_SLOTS:
28 public Q_SLOTS:
29 void handleSeriesChanged(const PieChangeSet& changeSet);
30 void handleDomainChanged(const Domain& domain);
30 void handleDomainChanged(const Domain& domain);
31 void handleGeometryChanged(const QRectF& rect);
31 void handleGeometryChanged(const QRectF& rect);
32
32
@@ -1,19 +1,37
1 #include "pieslice.h"
1 #include "pieslice.h"
2 #include "piepresenter.h"
2 #include "piepresenter.h"
3 #include "qpieseries.h"
3 #include <QPainter>
4 #include <QPainter>
4 #include <QDebug>
5 #include <QDebug>
6 #include <qmath.h>
5
7
6 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
7
9
8 PieSlice::PieSlice(PiePresenter *piePresentation, int seriesIndex, qreal startAngle, qreal span)
10 #define PI 3.14159265
9 :QGraphicsItem(piePresentation),
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 m_seriesIndex(seriesIndex),
23 m_seriesIndex(seriesIndex),
11 m_startAngle(startAngle),
24 m_startAngle(startAngle),
12 m_span(span)
25 m_span(span)
13 {
26 {
14 Q_ASSERT(piePresentation);
27 Q_ASSERT(presenter);
15 setAcceptHoverEvents(true);
28 setAcceptHoverEvents(true);
16 setAcceptedMouseButtons(Qt::LeftButton);
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 PieSlice::~PieSlice()
37 PieSlice::~PieSlice()
@@ -22,70 +40,85 PieSlice::~PieSlice()
22
40
23 QRectF PieSlice::boundingRect() const
41 QRectF PieSlice::boundingRect() const
24 {
42 {
25 return shape().boundingRect();
43 return m_rect;
26 }
44 }
27
45
28 QPainterPath PieSlice::shape() const
46 QPainterPath PieSlice::shape() const
29 {
47 {
30 QRectF rect = (static_cast<PiePresenter*>(parentItem()))->pieRect();
48 return m_path;
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;
49 }
49 }
50
50
51 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
51 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
52 {
52 {
53 painter->setRenderHint(QPainter::Antialiasing);
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
61
54
62 //painter->setBrush(m_theme.linePen.color());
55 // TODO: themes
63
56 painter->setPen(m_pen);
64 // From Qt docs:
57 painter->setBrush(m_brush);
65 // The startAngle and spanAngle must be specified in 1/16th of a degree, i.e. a full circle equals 5760 (16 * 360).
58 painter->drawPath(m_path);
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());
75
59
76 // Draw the label
60 // Draw the label
77 // TODO: do this better
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 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent * event)
66 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent * event)
82 {
67 {
83 QGraphicsItem::hoverEnterEvent(event);
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 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent *event)
80 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent *event)
88 {
81 {
89 QGraphicsItem::mousePressEvent(event);
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);
90 }
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);
117 }
118
119 QPieSlice PieSlice::sliceData()
120 {
121 return (static_cast<PiePresenter*>(parentItem()))->m_pieSeries->slice(m_seriesIndex);
122 }
123
91 QTCOMMERCIALCHART_END_NAMESPACE
124 QTCOMMERCIALCHART_END_NAMESPACE
@@ -3,9 +3,11
3
3
4 #include "qchartglobal.h"
4 #include "qchartglobal.h"
5 #include "charttheme_p.h"
5 #include "charttheme_p.h"
6 #include "qpieseries.h"
6 #include <QGraphicsItem>
7 #include <QGraphicsItem>
7 #include <QRectF>
8 #include <QRectF>
8 #include <QColor>
9 #include <QColor>
10 #include <QPen>
9
11
10 QTCOMMERCIALCHART_BEGIN_NAMESPACE
12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11 class PiePresenter;
13 class PiePresenter;
@@ -13,7 +15,7 class PiePresenter;
13 class PieSlice : public QGraphicsItem
15 class PieSlice : public QGraphicsItem
14 {
16 {
15 public:
17 public:
16 PieSlice(PiePresenter *piePresentation, int seriesIndex, qreal startAngle, qreal span);
18 PieSlice(PiePresenter *piePresenter, int seriesIndex, qreal startAngle, qreal span);
17 ~PieSlice();
19 ~PieSlice();
18
20
19 public: // from QGraphicsItem
21 public: // from QGraphicsItem
@@ -21,14 +23,25 public: // from QGraphicsItem
21 QPainterPath shape() const;
23 QPainterPath shape() const;
22 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
24 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
23 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
25 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
26 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
24 void mousePressEvent(QGraphicsSceneMouseEvent *event);
27 void mousePressEvent(QGraphicsSceneMouseEvent *event);
25
28
29 public:
30 void updateGeometry();
31
32 private:
33 QPieSlice sliceData();
34
26 private:
35 private:
36 QGraphicsTextItem* m_label;
27 int m_seriesIndex;
37 int m_seriesIndex;
28 qreal m_startAngle;
38 qreal m_startAngle;
29 qreal m_span;
39 qreal m_span;
40 QPainterPath m_path;
30 QRectF m_rect;
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 QTCOMMERCIALCHART_END_NAMESPACE
47 QTCOMMERCIALCHART_END_NAMESPACE
@@ -7,7 +7,6 QTCOMMERCIALCHART_BEGIN_NAMESPACE
7
7
8 QPieSeries::QPieSeries(QObject *parent) :
8 QPieSeries::QPieSeries(QObject *parent) :
9 QChartSeries(parent),
9 QChartSeries(parent),
10 m_piePresenter(0),
11 m_sizeFactor(1.0),
10 m_sizeFactor(1.0),
12 m_position(PiePositionMaximized)
11 m_position(PiePositionMaximized)
13 {
12 {
@@ -20,21 +19,30 QPieSeries::~QPieSeries()
20
19
21 void QPieSeries::set(QList<QPieSlice> slices)
20 void QPieSeries::set(QList<QPieSlice> slices)
22 {
21 {
23 m_slices = slices;
22 PieChangeSet changeSet;
24 if (m_piePresenter) {
23
25 m_piePresenter->seriesChanged();
24 for (int i=slices.count(); i<m_slices.count(); i++)
26 m_piePresenter->update();
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 void QPieSeries::add(QList<QPieSlice> slices)
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 m_slices += slices;
44 m_slices += slices;
33 if (m_piePresenter) {
45 emit changed(changeSet);
34 m_piePresenter->seriesChanged();
35 // TODO: m_piePresenter->seriesAppended()??
36 m_piePresenter->update();
37 }
38 }
46 }
39
47
40 void QPieSeries::add(QPieSlice slice)
48 void QPieSeries::add(QPieSlice slice)
@@ -53,12 +61,9 bool QPieSeries::update(int index, QPieSlice slice)
53 {
61 {
54 if ((index >= 0) && (index < m_slices.count())) {
62 if ((index >= 0) && (index < m_slices.count())) {
55 m_slices[index] = slice;
63 m_slices[index] = slice;
56 if (m_piePresenter) {
64 PieChangeSet changeSet;
57 m_piePresenter->seriesChanged();
65 changeSet.m_changed << index;
58 // TODO: for a nice animation we need something like
66 emit changed(changeSet);
59 // m_piePresenter->sliceChanged(index, oldslice, newslice)
60 m_piePresenter->update();
61 }
62 return true;
67 return true;
63 }
68 }
64 return false;
69 return false;
@@ -68,24 +73,13 void QPieSeries::setSizeFactor(qreal factor)
68 {
73 {
69 if (factor > 0.0)
74 if (factor > 0.0)
70 m_sizeFactor = factor;
75 m_sizeFactor = factor;
71
76 emit sizeFactorChanged();
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 }
78 }
77 }
79
78
80 void QPieSeries::setPosition(PiePosition position)
79 void QPieSeries::setPosition(PiePosition position)
81 {
80 {
82 m_position = position;
81 m_position = position;
83 if (m_piePresenter) {
82 emit positionChanged();
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 }
89 }
83 }
90
84
91 #include "moc_qpieseries.cpp"
85 #include "moc_qpieseries.cpp"
@@ -26,6 +26,14 public:
26 bool m_isExploded;
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 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QChartSeries
37 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QChartSeries
30 {
38 {
31 Q_OBJECT
39 Q_OBJECT
@@ -69,13 +77,14 public:
69 void setPosition(PiePosition position);
77 void setPosition(PiePosition position);
70 PiePosition position() const { return m_position; }
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 private:
85 private:
73 Q_DISABLE_COPY(QPieSeries)
86 Q_DISABLE_COPY(QPieSeries)
74 // TODO: use PIML
87 // TODO: use PIML
75 friend class ChartPresenter;
76 friend class ChartDataSet;
77 friend class PiePresenter;
78 PiePresenter *m_piePresenter;
79 QList<QPieSlice> m_slices;
88 QList<QPieSlice> m_slices;
80 qreal m_sizeFactor;
89 qreal m_sizeFactor;
81 PiePosition m_position;
90 PiePosition m_position;
General Comments 0
You need to be logged in to leave comments. Login now