##// END OF EJS Templates
Fixed paint and mouse event issues with QLineSeries...
Tero Ahola -
r1791:877b494897a0
parent child
Show More
@@ -1,101 +1,103
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include <QValuesAxis>
22 22 #include <QAbstractAxis>
23 #include <cmath>
23 24 #include <QDebug>
24 25
25 26 #include "chart.h"
26 27
27 28 Chart::Chart(QGraphicsItem *parent, Qt::WindowFlags wFlags, QLineSeries *series)
28 29 : QChart(parent, wFlags), m_series(series)
29 30 {
30 31 m_clicked = false;
31 32 }
32 33
33 34 Chart::~Chart()
34 35 {
35 36 }
36 37
37 38 void Chart::clickPoint(const QPointF &point)
38 39 {
39 //Get all points from the series.
40 QList<QPointF> points = m_series->points();
41 //Construct a small rectangle around the clicked point
42 //to identify the real point clicked from the series.
43 QRectF clickRect(point.x() - 0.5, point.y() - 0.5, 1.0, 1.0);
44
45 //Find the clicked point to be moved.
46 foreach (QPointF p, points) {
47 if (clickRect.contains(p)) {
40 // Find the closes data point
41 m_movingPoint = QPoint();
42 m_clicked = false;
43 foreach (QPointF p, m_series->points()) {
44 if (distance(p, point) < distance(m_movingPoint, point)) {
48 45 m_movingPoint = p;
49 46 m_clicked = true;
50 return;
51 47 }
52 48 }
53 49 }
54 50
51 qreal Chart::distance(const QPointF &p1, const QPointF &p2)
52 {
53 return sqrt((p1.x() - p2.x()) * (p1.x() - p2.x())
54 + (p1.y() - p2.y()) * (p1.y() - p2.y()));
55 }
56
55 57 void Chart::setPointClicked(bool clicked)
56 58 {
57 59 m_clicked = clicked;
58 60 }
59 61
60 62 void Chart::handlePointMove(const QPoint &point)
61 63 {
62 64 if (m_clicked) {
63 65 //Map the point clicked from the ChartView
64 66 //to the area occupied by the chart.
65 67 QPoint mappedPoint = point;
66 68 mappedPoint.setX(point.x()-this->plotArea().x());
67 69 mappedPoint.setY(point.y()-this->plotArea().y());
68 70
69 71 //Get the x- and y axis to be able to convert the mapped
70 72 //coordinate point to the charts scale.
71 73 QAbstractAxis * axisx = this->axisX();
72 74 QValuesAxis* haxis = 0;
73 75 if (axisx->type() == QAbstractAxis::AxisTypeValues)
74 76 haxis = qobject_cast<QValuesAxis*>(axisx);
75 77
76 78 QAbstractAxis * axisy = this->axisY();
77 79 QValuesAxis* vaxis = 0;
78 80 if (axisy->type() == QAbstractAxis::AxisTypeValues)
79 81 vaxis = qobject_cast<QValuesAxis*>(axisy);
80 82
81 83 if (haxis && vaxis) {
82 84 //Calculate the "unit" between points on the x
83 85 //y axis.
84 86 double xUnit = this->plotArea().width()/haxis->max();
85 87 double yUnit = this->plotArea().height()/vaxis->max();
86 88
87 89 //Convert the mappedPoint to the actual chart scale.
88 90 double x = mappedPoint.x()/xUnit;
89 91 double y = vaxis->max() - mappedPoint.y()/yUnit;
90 92
91 93 //Replace the old point with the new one.
92 94 m_series->replace(m_movingPoint, QPointF(x, y));
93 95
94 96 //Update the m_movingPoint so we are able to
95 97 //do the replace also during mousemoveEvent.
96 98 m_movingPoint.setX(x);
97 99 m_movingPoint.setY(y);
98 100 }
99 101 }
100 102 }
101 103
@@ -1,52 +1,53
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #ifndef CHART_H
22 22 #define CHART_H
23 23
24 24 #include <QChart>
25 25 #include <QLineSeries>
26 26
27 27 QTCOMMERCIALCHART_USE_NAMESPACE
28 28
29 29 class Chart : public QChart
30 30 {
31 31 Q_OBJECT
32 32 public:
33 33 explicit Chart(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0, QLineSeries *series = 0);
34 34 ~Chart();
35 35
36 36 public slots:
37 37 void clickPoint(const QPointF &point);
38 38
39 39 public:
40 40 void handlePointMove(const QPoint &point);
41 41 void setPointClicked(bool clicked);
42 42
43 43 private:
44 qreal distance(const QPointF &p1, const QPointF &p2);
44 45 QLineSeries *m_series;
45 46 QPointF m_movingPoint;
46 47
47 48 //Boolean value to determine if an actual point in the
48 49 //series is clicked.
49 50 bool m_clicked;
50 51 };
51 52
52 53 #endif // CHART_H
@@ -1,71 +1,74
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include <QApplication>
22 22 #include <QMainWindow>
23 23 #include <QLineSeries>
24 24
25 25 #include <QValuesAxis>
26 26
27 27 #include "chart.h"
28 28 #include "chartview.h"
29 29
30 30 QTCOMMERCIALCHART_USE_NAMESPACE
31 31
32 32 int main(int argc, char *argv[])
33 33 {
34 34 QApplication a(argc, argv);
35 35
36 36 QLineSeries* series = new QLineSeries();
37 37
38 38 series->append(0, 6);
39 39 series->append(1, 3);
40 40 series->append(2, 4);
41 41 series->append(3, 8);
42 42 series->append(7, 13);
43 43 series->append(10, 5);
44 44 *series << QPointF(11, 1) << QPointF(13, 3) << QPointF(17, 6) << QPointF(18, 3) << QPointF(20, 2);
45 45
46 46 Chart* chart = new Chart(0, 0, series);
47 47 chart->legend()->hide();
48 48 chart->addSeries(series);
49 QPen p = series->pen();
50 p.setWidth(5);
51 series->setPen(p);
49 52 chart->createDefaultAxes();
50 53 chart->setTitle("Drag'n drop to move data points");
51 54
52 55 QValuesAxis *axisX = new QValuesAxis();
53 56 chart->setAxisX(axisX, series);
54 57 axisX->setRange(0, 20);
55 58
56 59 QValuesAxis *axisY = new QValuesAxis();
57 60 chart->setAxisY(axisY, series);
58 61 axisY->setRange(0, 13);
59 62
60 63 QObject::connect(series, SIGNAL(clicked(QPointF)), chart, SLOT(clickPoint(QPointF)));
61 64
62 65 ChartView* chartView = new ChartView(chart);
63 66 chartView->setRenderHint(QPainter::Antialiasing);
64 67
65 68 QMainWindow window;
66 69 window.setCentralWidget(chartView);
67 70 window.resize(400, 300);
68 71 window.show();
69 72
70 73 return a.exec();
71 74 }
@@ -1,119 +1,132
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "linechartitem_p.h"
22 22 #include "qlineseries.h"
23 23 #include "qlineseries_p.h"
24 24 #include "chartpresenter_p.h"
25 25 #include <QPainter>
26 26 #include <QGraphicsSceneMouseEvent>
27 27
28
29 28 QTCOMMERCIALCHART_BEGIN_NAMESPACE
30 29
31 //TODO: optimize : remove points which are not visible
30 const qreal mouseEventMinWidth(14);
32 31
33 32 LineChartItem::LineChartItem(QLineSeries* series,ChartPresenter *presenter):
34 33 XYChart(series, presenter),
35 34 QGraphicsItem(presenter ? presenter->rootItem() : 0),
36 35 m_series(series),
37 36 m_pointsVisible(false)
38 37 {
39 38 setZValue(ChartPresenter::LineChartZValue);
40 39 QObject::connect(series->d_func(),SIGNAL(updated()),this,SLOT(handleUpdated()));
41 40 QObject::connect(series, SIGNAL(visibleChanged()), this, SLOT(handleUpdated()));
42 41 handleUpdated();
43 42 }
44 43
45 44 QRectF LineChartItem::boundingRect() const
46 45 {
47 46 return m_rect;
48 47 }
49 48
50 49 QPainterPath LineChartItem::shape() const
51 50 {
52 return m_path;
51 // Increase the size of the path slightly to make mouse interactions more natural
52 QPainterPathStroker s;
53 s.setCapStyle(Qt::RoundCap);
54 s.setJoinStyle(Qt::RoundJoin);
55 qreal spacing = qMax(mouseEventMinWidth, (qreal) m_linePen.width());
56 s.setWidth(spacing);
57 return s.createStroke(m_path);
53 58 }
54 59
55 60 void LineChartItem::updateGeometry()
56 61 {
57 62 const QVector<QPointF>& points = geometryPoints();
58 63
59 64 if(points.size()==0)
60 65 {
61 66 prepareGeometryChange();
62 67 m_path = QPainterPath();
63 68 m_rect = QRect();
64 69 return;
65 70 }
66 71
67 72 QPainterPath linePath(points.at(0));
68 73
69 74 for(int i=1; i< points.size();i++) {
70 75 linePath.lineTo(points.at(i));
71 76 }
72 77
73 78 prepareGeometryChange();
79
74 80 m_path = linePath;
75 m_rect = linePath.boundingRect();
81
82 // When defining bounding rectangle,
83 // 1. take the line width into account (otherwise you will get drawing artifacts) and
84 // 2. take the shape into account (otherwise you will not get mouse events through on border
85 // areas).
86 const qreal sqrtOf2 = 1.414214;
87 const qreal spacing = qMax(mouseEventMinWidth / 2.0,
88 sqrtOf2 * (qreal) m_linePen.width() / 2.0);
89 m_rect = m_path.boundingRect().adjusted(-spacing, -spacing, spacing, spacing);
90
76 91 setPos(origin());
77 92 }
78 93
79 94 void LineChartItem::handleUpdated()
80 95 {
81 96 setVisible(m_series->isVisible());
82 97 m_pointsVisible = m_series->pointsVisible();
83 98 m_linePen = m_series->pen();
84 99 m_pointPen = m_series->pen();
85 100 m_pointPen.setWidthF(2*m_pointPen.width());
86 101 update();
87 102 }
88 103
89 //painter
90
91 104 void LineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
92 105 {
93 106 Q_UNUSED(widget)
94 107 Q_UNUSED(option)
95 108
96 109 painter->save();
97 110 painter->setPen(m_linePen);
98 111 painter->setClipRect(clipRect());
99 112 // Draw lines
100 113 const QVector<QPointF> &points = geometryPoints();
101 114 for (int i(1); i < points.size();i++)
102 115 painter->drawLine(points.at(i-1), points.at(i));
103 116 // Draw points
104 117 if (m_pointsVisible){
105 118 painter->setPen(m_pointPen);
106 119 painter->drawPoints(geometryPoints());
107 120 }
108 121 painter->restore();
109 122 }
110 123
111 124 void LineChartItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
112 125 {
113 126 emit XYChart::clicked(calculateDomainPoint(event->pos()));
114 127 QGraphicsItem::mousePressEvent(event);
115 128 }
116 129
117 130 #include "moc_linechartitem_p.cpp"
118 131
119 132 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,73 +1,73
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 // W A R N I N G
22 22 // -------------
23 23 //
24 24 // This file is not part of the QtCommercial Chart API. It exists purely as an
25 25 // implementation detail. This header file may change from version to
26 26 // version without notice, or even be removed.
27 27 //
28 28 // We mean it.
29 29
30 30 #ifndef LINECHARTITEM_H
31 31 #define LINECHARTITEM_H
32 32
33 33 #include "qchartglobal.h"
34 34 #include "xychart_p.h"
35 35 #include <QPen>
36 36
37 37 QTCOMMERCIALCHART_BEGIN_NAMESPACE
38 38
39 39 class QLineSeries;
40 40 class ChartPresenter;
41 41
42 42 class LineChartItem : public XYChart , public QGraphicsItem
43 43 {
44 44 Q_OBJECT
45 45 Q_INTERFACES(QGraphicsItem)
46 46 public:
47 47 explicit LineChartItem(QLineSeries *series,ChartPresenter *presenter);
48 ~LineChartItem() {};
48 ~LineChartItem() {}
49 49
50 50 //from QGraphicsItem
51 51 QRectF boundingRect() const;
52 52 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
53 53 QPainterPath shape() const;
54 54
55 55 public Q_SLOTS:
56 56 void handleUpdated();
57 57 protected:
58 58 void updateGeometry();
59 59 void mousePressEvent(QGraphicsSceneMouseEvent *event);
60 60
61 61 private:
62 62 QLineSeries* m_series;
63 63 QPainterPath m_path;
64 64 QRectF m_rect;
65 65 QPen m_linePen;
66 66 QPen m_pointPen;
67 67 bool m_pointsVisible;
68 68
69 69 };
70 70
71 71 QTCOMMERCIALCHART_END_NAMESPACE
72 72
73 73 #endif
General Comments 0
You need to be logged in to leave comments. Login now