##// 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 12 multichart \
13 13 gdpbarchart \
14 14 presenterchart \
15 chartview
15 chartview \
16 scatterinteractions
@@ -14,15 +14,9 int main(int argc, char *argv[])
14 14 // Create chart view
15 15 QChartView *chartView = new QChartView();
16 16 chartView->setChartTheme(QChart::ChartThemeIcy);
17
18 17 // Add scatter series with simple test data
19 18 QScatterSeries *scatter = new QScatterSeries();
20 *scatter << QPointF(0.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);
19 *scatter << QPointF(0.5, 5.0) << QPointF(1.0, 4.5) << QPointF(1.0, 5.5) << QPointF(1.5, 5.0);
26 20 // Chart takes ownership
27 21 chartView->addSeries(scatter);
28 22 //! [1]
@@ -54,8 +48,9 int main(int argc, char *argv[])
54 48
55 49 // Use the chart widget as the central widget
56 50 QMainWindow w;
57 w.resize(640, 480);
51 w.resize(400, 300);
58 52 w.setCentralWidget(chartView);
53 w.setWindowFlags(Qt::FramelessWindowHint);
59 54 w.show();
60 55
61 56 return a.exec();
@@ -3,6 +3,3
3 3 }
4 4 TARGET = scatter
5 5 SOURCES += main.cpp
6
7
8
@@ -166,7 +166,8 void ChartPresenter::handleSeriesAdded(QSeries* series)
166 166 case QSeries::SeriesTypeScatter: {
167 167 QScatterSeries *scatterSeries = qobject_cast<QScatterSeries *>(series);
168 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 171 QObject::connect(this, SIGNAL(geometryChanged(const QRectF&)),
171 172 scatterPresenter, SLOT(handleGeometryChanged(const QRectF&)));
172 173 m_chartTheme->decorate(scatterPresenter, scatterSeries, m_chartItems.count());
@@ -36,8 +36,10
36 36 */
37 37
38 38 /*!
39 \fn void QScatterSeries::clicked()
40 \brief TODO
39 \fn void QScatterSeries::clicked(QPointF coordinate)
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 200 Overrides the default pen used for drawing a marker item with a user defined \a pen. The
146 201 default pen is defined by chart theme setting.
147 202
@@ -40,7 +40,11 public:
40 40 QScatterSeries& operator << (const QPointF &value);
41 41 QScatterSeries& operator << (QList<QPointF> points);
42 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 49 QPen pen();
46 50 void setPen(QPen pen);
@@ -51,7 +55,7 public:
51 55 // TODO: marker size?
52 56
53 57 Q_SIGNALS:
54 void clicked(/* TODO: parameters? */);
58 void clicked(QPointF coordinate);
55 59 // TODO: move to PIMPL for simplicity or does the user ever need changed signals?
56 60 // TODO: more finegrained signaling for performance reasons
57 61 // (check QPieSeries implementation with change sets)
@@ -41,8 +41,9 void ScatterPresenter::handleDomainChanged(const Domain& domain)
41 41
42 42 void ScatterPresenter::handleGeometryChanged(const QRectF& rect)
43 43 {
44 m_boundingRect = rect;
44 m_boundingRect = rect.translated(-rect.topLeft());
45 45 changeGeometry();
46 setPos(rect.topLeft());
46 47 }
47 48
48 49 void ScatterPresenter::handleModelChanged()
@@ -90,11 +91,16 void ScatterPresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem *
90 91
91 92 void ScatterPresenter::mousePressEvent(QGraphicsSceneMouseEvent *event)
92 93 {
93 qDebug() << "ScatterPresenter::mousePressEvent" << event << " cont: "
94 << m_path.contains(event->lastPos());
94 // Empty implementation to grab mouse release events for this item
95 Q_UNUSED(event)
96 }
95 97
96 if (m_path.contains(event->lastPos()))
97 emit clicked();
98 void ScatterPresenter::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
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 106 void ScatterPresenter::changeGeometry()
@@ -107,28 +113,29 void ScatterPresenter::changeGeometry()
107 113 int shape = m_series->shape();
108 114 m_path = QPainterPath();
109 115 m_path.setFillRule(Qt::WindingFill);
116 const qreal size(9); // TODO: user defined size?
110 117
111 118 foreach (QPointF point, m_series->data()) {
112 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;
114 qreal y = m_boundingRect.bottom() - point.y() * scaley + m_visibleChartArea.m_minY * scaley;
120 qreal x = point.x() * scalex - m_visibleChartArea.m_minX * scalex - size / 2;
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 124 switch (shape) {
118 125 case QScatterSeries::MarkerShapeDefault:
119 126 // Fallthrough, defaults to circle
120 127 case QScatterSeries::MarkerShapeCircle:
121 m_path.addEllipse(x, y, 9, 9);
128 m_path.addEllipse(x, y, size, size);
122 129 break;
123 130 case QScatterSeries::MarkerShapePoint:
124 131 m_path.addEllipse(x, y, 2, 2);
125 132 break;
126 133 case QScatterSeries::MarkerShapeRectangle:
127 m_path.addRect(x, y, 9, 9);
134 m_path.addRect(x, y, size, size);
128 135 break;
129 136 case QScatterSeries::MarkerShapeTiltedRectangle: {
130 137 // TODO: tilt the rectangle
131 m_path.addRect(x, y, 9, 9);
138 m_path.addRect(x, y, size, size);
132 139 break;
133 140 }
134 141 default:
@@ -10,10 +10,6 QTCOMMERCIALCHART_BEGIN_NAMESPACE
10 10
11 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 13 class ScatterPresenter : public QObject, public ChartItem
18 14 {
19 15 Q_OBJECT
@@ -21,13 +17,14 public:
21 17 explicit ScatterPresenter(QScatterSeries *series, QGraphicsObject *parent = 0);
22 18
23 19 public: // from ChartItem
24 QRectF boundingRect() const { return m_path.boundingRect(); }
20 QRectF boundingRect() const { return m_path.controlPointRect(); }
25 21 QPainterPath shape() const { return m_path; }
26 22 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
27 23 void mousePressEvent (QGraphicsSceneMouseEvent * event);
24 void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
28 25
29 26 Q_SIGNALS:
30 void clicked();
27 void clicked(QPointF coordinates);
31 28
32 29 public Q_SLOTS:
33 30 void handleDomainChanged(const Domain& domain);
General Comments 0
You need to be logged in to leave comments. Login now