##// END OF EJS Templates
Clicked, remove and clear to QScatterSeries
Tero Ahola -
r394:9882bdf19567
parent child
Show More
@@ -0,0 +1,11
1 #include <QtGui/QApplication>
2 #include "mainwindow.h"
3
4 int main(int argc, char *argv[])
5 {
6 QApplication a(argc, argv);
7 MainWindow w;
8 w.show();
9
10 return a.exec();
11 }
@@ -0,0 +1,51
1 #include "mainwindow.h"
2 #include <qchartglobal.h>
3 #include <qchartview.h>
4 #include <QDebug>
5
6 QTCOMMERCIALCHART_USE_NAMESPACE
7
8 MainWindow::MainWindow(QWidget *parent)
9 : QMainWindow(parent)
10 {
11 resize(400, 300);
12 setWindowFlags(Qt::FramelessWindowHint);
13
14 QChartView *chartView = new QChartView(this);
15 chartView->setChartTitle("Click to play with points");
16 chartView->setRenderHint(QPainter::Antialiasing);
17 setCentralWidget(chartView);
18
19 m_scatter = new QScatterSeries();
20 for(qreal x(0.5); x <= 5.0; x += 0.5) {
21 for(qreal y(0.5); y <= 5.0; y += 0.5) {
22 *m_scatter << QPointF(x, y);
23 }
24 }
25 chartView->addSeries(m_scatter);
26
27 // Add two more series
28 m_scatter2 = new QScatterSeries();
29 chartView->addSeries(m_scatter2);
30 m_scatter3 = new QScatterSeries();
31 chartView->addSeries(m_scatter3);
32
33 connect(m_scatter, SIGNAL(clicked(QPointF)), this, SLOT(clickPoint(QPointF)));
34 }
35
36 MainWindow::~MainWindow()
37 {
38 }
39
40 void MainWindow::clickPoint(QPointF coordinate)
41 {
42 // Remove the clicked point from the series and add points to the two other series we have
43 int index = m_scatter->closestPoint(coordinate);
44 QPointF point = m_scatter->data().at(index);
45 Q_ASSERT(m_scatter->removeAt(index));
46 point.rx() += 0.25;
47 point.ry() += 0.25;
48 *m_scatter2 << point;
49 point.ry() -= 0.25;
50 *m_scatter3 << point;
51 }
@@ -0,0 +1,27
1 #ifndef MAINWINDOW_H
2 #define MAINWINDOW_H
3
4 #include <QtGui/QMainWindow>
5 #include <qchartglobal.h>
6 #include <qscatterseries.h>
7
8 QTCOMMERCIALCHART_USE_NAMESPACE
9
10 class MainWindow : public QMainWindow
11 {
12 Q_OBJECT
13
14 public:
15 MainWindow(QWidget *parent = 0);
16 ~MainWindow();
17
18 private Q_SLOTS:
19 void clickPoint(QPointF coordinate);
20
21 private:
22 QScatterSeries *m_scatter;
23 QScatterSeries *m_scatter2;
24 QScatterSeries *m_scatter3;
25 };
26
27 #endif // MAINWINDOW_H
@@ -0,0 +1,12
1 !include( ../example.pri ) {
2 error( "Couldn't find the example.pri file!" )
3 }
4 QT += core gui
5
6 TARGET = scatterinteractions
7 TEMPLATE = app
8
9 SOURCES += main.cpp\
10 mainwindow.cpp
11
12 HEADERS += mainwindow.h
@@ -12,4 +12,5 SUBDIRS += linechart \
12 multichart \
12 multichart \
13 gdpbarchart \
13 gdpbarchart \
14 presenterchart \
14 presenterchart \
15 chartview
15 chartview \
16 scatterinteractions
@@ -14,15 +14,9 int main(int argc, char *argv[])
14 // Create chart view
14 // Create chart view
15 QChartView *chartView = new QChartView();
15 QChartView *chartView = new QChartView();
16 chartView->setChartTheme(QChart::ChartThemeIcy);
16 chartView->setChartTheme(QChart::ChartThemeIcy);
17
18 // Add scatter series with simple test data
17 // Add scatter series with simple test data
19 QScatterSeries *scatter = new QScatterSeries();
18 QScatterSeries *scatter = new QScatterSeries();
20 *scatter << QPointF(0.5, 5.0)
19 *scatter << QPointF(0.5, 5.0) << QPointF(1.0, 4.5) << QPointF(1.0, 5.5) << QPointF(1.5, 5.0);
21 << QPointF(1.0, 4.5)
22 << QPointF(1.0, 5.5)
23 << QPointF(1.5, 5.0)
24 << QPointF(2.0, 4.5)
25 << QPointF(2.5, 5.0);
26 // Chart takes ownership
20 // Chart takes ownership
27 chartView->addSeries(scatter);
21 chartView->addSeries(scatter);
28 //! [1]
22 //! [1]
@@ -54,8 +48,9 int main(int argc, char *argv[])
54
48
55 // Use the chart widget as the central widget
49 // Use the chart widget as the central widget
56 QMainWindow w;
50 QMainWindow w;
57 w.resize(640, 480);
51 w.resize(400, 300);
58 w.setCentralWidget(chartView);
52 w.setCentralWidget(chartView);
53 w.setWindowFlags(Qt::FramelessWindowHint);
59 w.show();
54 w.show();
60
55
61 return a.exec();
56 return a.exec();
@@ -1,8 +1,5
1 !include( ../example.pri ) {
1 !include( ../example.pri ) {
2 error( "Couldn't find the example.pri file!" )
2 error( "Couldn't find the example.pri file!" )
3 }
3 }
4 TARGET = scatter
4 TARGET = scatter
5 SOURCES += main.cpp
5 SOURCES += main.cpp
6
7
8
@@ -166,7 +166,8 void ChartPresenter::handleSeriesAdded(QSeries* series)
166 case QSeries::SeriesTypeScatter: {
166 case QSeries::SeriesTypeScatter: {
167 QScatterSeries *scatterSeries = qobject_cast<QScatterSeries *>(series);
167 QScatterSeries *scatterSeries = qobject_cast<QScatterSeries *>(series);
168 ScatterPresenter *scatterPresenter = new ScatterPresenter(scatterSeries, m_chart);
168 ScatterPresenter *scatterPresenter = new ScatterPresenter(scatterSeries, m_chart);
169 QObject::connect(scatterPresenter, SIGNAL(clicked()), scatterSeries, SIGNAL(clicked()));
169 QObject::connect(scatterPresenter, SIGNAL(clicked(QPointF)),
170 scatterSeries, SIGNAL(clicked(QPointF)));
170 QObject::connect(this, SIGNAL(geometryChanged(const QRectF&)),
171 QObject::connect(this, SIGNAL(geometryChanged(const QRectF&)),
171 scatterPresenter, SLOT(handleGeometryChanged(const QRectF&)));
172 scatterPresenter, SLOT(handleGeometryChanged(const QRectF&)));
172 m_chartTheme->decorate(scatterPresenter, scatterSeries, m_chartItems.count());
173 m_chartTheme->decorate(scatterPresenter, scatterSeries, m_chartItems.count());
@@ -36,8 +36,10
36 */
36 */
37
37
38 /*!
38 /*!
39 \fn void QScatterSeries::clicked()
39 \fn void QScatterSeries::clicked(QPointF coordinate)
40 \brief TODO
40 User clicked the scatter series. Note that the \a coordinate is the chart coordinate that the
41 click occurred on; not necessarily a data point coordinate. To find the corresponding (closest)
42 data point you can use closestPoint().
41 */
43 */
42
44
43 /*!
45 /*!
@@ -142,6 +144,59 QList<QPointF> QScatterSeries::data()
142 }
144 }
143
145
144 /*!
146 /*!
147 Remove the data point at \a pointIndex. Returns true if a point was removed, false if the point
148 at \a pointIndex does not exist on the series.
149 */
150 bool QScatterSeries::removeAt(int pointIndex)
151 {
152 if (pointIndex >=0 && pointIndex < d->m_data.count()) {
153 d->m_data.removeAt(pointIndex);
154 emit changed();
155 return true;
156 }
157 return false;
158 }
159
160 /*!
161 Remove all occurrences of \a point from the series and returns the number of points removed.
162 */
163 int QScatterSeries::removeAll(QPointF point)
164 {
165 int count = d->m_data.removeAll(point);
166 emit changed();
167 return count;
168 }
169
170 /*!
171 Remove all data points from the series.
172 */
173 void QScatterSeries::clear()
174 {
175 d->m_data.clear();
176 emit changed();
177 }
178
179 /*!
180 Returns the index of the data point that is closest to \a coordinate. If several data points
181 are at the same distance from the \a coordinate, returns the last one. If no points exist,
182 returns -1.
183 */
184 int QScatterSeries::closestPoint(QPointF coordinate)
185 {
186 qreal distance(-1);
187 int pointIndex(-1);
188 for (int i(0); i < d->m_data.count(); i++) {
189 QPointF dataPoint = d->m_data.at(i);
190 QPointF difference = dataPoint - coordinate;
191 if (i == 0 || difference.manhattanLength() <= distance) {
192 distance = difference.manhattanLength();
193 pointIndex = i;
194 }
195 }
196 return pointIndex;
197 }
198
199 /*!
145 Overrides the default pen used for drawing a marker item with a user defined \a pen. The
200 Overrides the default pen used for drawing a marker item with a user defined \a pen. The
146 default pen is defined by chart theme setting.
201 default pen is defined by chart theme setting.
147
202
@@ -40,7 +40,11 public:
40 QScatterSeries& operator << (const QPointF &value);
40 QScatterSeries& operator << (const QPointF &value);
41 QScatterSeries& operator << (QList<QPointF> points);
41 QScatterSeries& operator << (QList<QPointF> points);
42 QList<QPointF> data();
42 QList<QPointF> data();
43 //TODO: insert, replace, remove, clear...?
43 bool removeAt(int pointIndex);
44 int removeAll(QPointF point);
45 void clear();
46 int closestPoint(QPointF coordinate);
47 //TODO: insert, replace...?
44
48
45 QPen pen();
49 QPen pen();
46 void setPen(QPen pen);
50 void setPen(QPen pen);
@@ -51,7 +55,7 public:
51 // TODO: marker size?
55 // TODO: marker size?
52
56
53 Q_SIGNALS:
57 Q_SIGNALS:
54 void clicked(/* TODO: parameters? */);
58 void clicked(QPointF coordinate);
55 // TODO: move to PIMPL for simplicity or does the user ever need changed signals?
59 // TODO: move to PIMPL for simplicity or does the user ever need changed signals?
56 // TODO: more finegrained signaling for performance reasons
60 // TODO: more finegrained signaling for performance reasons
57 // (check QPieSeries implementation with change sets)
61 // (check QPieSeries implementation with change sets)
@@ -41,8 +41,9 void ScatterPresenter::handleDomainChanged(const Domain& domain)
41
41
42 void ScatterPresenter::handleGeometryChanged(const QRectF& rect)
42 void ScatterPresenter::handleGeometryChanged(const QRectF& rect)
43 {
43 {
44 m_boundingRect = rect;
44 m_boundingRect = rect.translated(-rect.topLeft());
45 changeGeometry();
45 changeGeometry();
46 setPos(rect.topLeft());
46 }
47 }
47
48
48 void ScatterPresenter::handleModelChanged()
49 void ScatterPresenter::handleModelChanged()
@@ -90,11 +91,16 void ScatterPresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem *
90
91
91 void ScatterPresenter::mousePressEvent(QGraphicsSceneMouseEvent *event)
92 void ScatterPresenter::mousePressEvent(QGraphicsSceneMouseEvent *event)
92 {
93 {
93 qDebug() << "ScatterPresenter::mousePressEvent" << event << " cont: "
94 // Empty implementation to grab mouse release events for this item
94 << m_path.contains(event->lastPos());
95 Q_UNUSED(event)
96 }
95
97
96 if (m_path.contains(event->lastPos()))
98 void ScatterPresenter::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
97 emit clicked();
99 {
100 QPointF clickedPoint(
101 m_visibleChartArea.m_minX + (event->lastPos().x() / m_boundingRect.width()) * m_visibleChartArea.spanX(),
102 m_visibleChartArea.m_maxY - (event->lastPos().y() / m_boundingRect.height()) * m_visibleChartArea.spanY());
103 emit clicked(clickedPoint);
98 }
104 }
99
105
100 void ScatterPresenter::changeGeometry()
106 void ScatterPresenter::changeGeometry()
@@ -107,28 +113,29 void ScatterPresenter::changeGeometry()
107 int shape = m_series->shape();
113 int shape = m_series->shape();
108 m_path = QPainterPath();
114 m_path = QPainterPath();
109 m_path.setFillRule(Qt::WindingFill);
115 m_path.setFillRule(Qt::WindingFill);
116 const qreal size(9); // TODO: user defined size?
110
117
111 foreach (QPointF point, m_series->data()) {
118 foreach (QPointF point, m_series->data()) {
112 // Convert relative coordinates to absolute pixel coordinates that can be used for drawing
119 // Convert relative coordinates to absolute pixel coordinates that can be used for drawing
113 qreal x = m_boundingRect.left() + point.x() * scalex - m_visibleChartArea.m_minX * scalex;
120 qreal x = point.x() * scalex - m_visibleChartArea.m_minX * scalex - size / 2;
114 qreal y = m_boundingRect.bottom() - point.y() * scaley + m_visibleChartArea.m_minY * scaley;
121 qreal y = m_boundingRect.height() - point.y() * scaley + m_visibleChartArea.m_minY * scaley - size / 2;
115
122
116 if (scene()->width() > x && scene()->height() > y) {
123 if (x < scene()->width() && y < scene()->height()) {
117 switch (shape) {
124 switch (shape) {
118 case QScatterSeries::MarkerShapeDefault:
125 case QScatterSeries::MarkerShapeDefault:
119 // Fallthrough, defaults to circle
126 // Fallthrough, defaults to circle
120 case QScatterSeries::MarkerShapeCircle:
127 case QScatterSeries::MarkerShapeCircle:
121 m_path.addEllipse(x, y, 9, 9);
128 m_path.addEllipse(x, y, size, size);
122 break;
129 break;
123 case QScatterSeries::MarkerShapePoint:
130 case QScatterSeries::MarkerShapePoint:
124 m_path.addEllipse(x, y, 2, 2);
131 m_path.addEllipse(x, y, 2, 2);
125 break;
132 break;
126 case QScatterSeries::MarkerShapeRectangle:
133 case QScatterSeries::MarkerShapeRectangle:
127 m_path.addRect(x, y, 9, 9);
134 m_path.addRect(x, y, size, size);
128 break;
135 break;
129 case QScatterSeries::MarkerShapeTiltedRectangle: {
136 case QScatterSeries::MarkerShapeTiltedRectangle: {
130 // TODO: tilt the rectangle
137 // TODO: tilt the rectangle
131 m_path.addRect(x, y, 9, 9);
138 m_path.addRect(x, y, size, size);
132 break;
139 break;
133 }
140 }
134 default:
141 default:
@@ -10,10 +10,6 QTCOMMERCIALCHART_BEGIN_NAMESPACE
10
10
11 class QScatterSeries;
11 class QScatterSeries;
12
12
13 /*!
14 * The "business logic" of scatter series. This is a QObject that does not have a parent QObject.
15 * The QGraphicsItem parent owns the object instead.
16 */
17 class ScatterPresenter : public QObject, public ChartItem
13 class ScatterPresenter : public QObject, public ChartItem
18 {
14 {
19 Q_OBJECT
15 Q_OBJECT
@@ -21,13 +17,14 public:
21 explicit ScatterPresenter(QScatterSeries *series, QGraphicsObject *parent = 0);
17 explicit ScatterPresenter(QScatterSeries *series, QGraphicsObject *parent = 0);
22
18
23 public: // from ChartItem
19 public: // from ChartItem
24 QRectF boundingRect() const { return m_path.boundingRect(); }
20 QRectF boundingRect() const { return m_path.controlPointRect(); }
25 QPainterPath shape() const { return m_path; }
21 QPainterPath shape() const { return m_path; }
26 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
22 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
27 void mousePressEvent (QGraphicsSceneMouseEvent * event);
23 void mousePressEvent (QGraphicsSceneMouseEvent * event);
24 void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
28
25
29 Q_SIGNALS:
26 Q_SIGNALS:
30 void clicked();
27 void clicked(QPointF coordinates);
31
28
32 public Q_SLOTS:
29 public Q_SLOTS:
33 void handleDomainChanged(const Domain& domain);
30 void handleDomainChanged(const Domain& domain);
General Comments 0
You need to be logged in to leave comments. Login now