@@ -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( |
|
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(); |
@@ -3,6 +3,3 | |||||
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()), |
|
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 = |
|
120 | qreal x = point.x() * scalex - m_visibleChartArea.m_minX * scalex - size / 2; | |
114 |
qreal y = m_boundingRect. |
|
121 | qreal y = m_boundingRect.height() - point.y() * scaley + m_visibleChartArea.m_minY * scaley - size / 2; | |
115 |
|
122 | |||
116 |
if (scene()->width() |
|
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, |
|
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, |
|
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, |
|
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. |
|
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