From 877b494897a01b1b7d948410ca7d47285191d6d9 2012-08-16 09:49:51 From: Tero Ahola Date: 2012-08-16 09:49:51 Subject: [PATCH] Fixed paint and mouse event issues with QLineSeries 1. The bounding rectangle of QLineSeries item did not take line width into account; this caused paint issues if the width is bigger than 1. 2. The width of the shape of the item was always 1. This caused problems with mouse events; onClicked was not always signaled, even if you click on top (but not in the middle of) a thick line series. --- diff --git a/demos/chartinteractions/chart.cpp b/demos/chartinteractions/chart.cpp index 986f5ae..38c4064 100644 --- a/demos/chartinteractions/chart.cpp +++ b/demos/chartinteractions/chart.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include "chart.h" @@ -36,22 +37,23 @@ Chart::~Chart() void Chart::clickPoint(const QPointF &point) { - //Get all points from the series. - QList points = m_series->points(); - //Construct a small rectangle around the clicked point - //to identify the real point clicked from the series. - QRectF clickRect(point.x() - 0.5, point.y() - 0.5, 1.0, 1.0); - - //Find the clicked point to be moved. - foreach (QPointF p, points) { - if (clickRect.contains(p)) { + // Find the closes data point + m_movingPoint = QPoint(); + m_clicked = false; + foreach (QPointF p, m_series->points()) { + if (distance(p, point) < distance(m_movingPoint, point)) { m_movingPoint = p; m_clicked = true; - return; } } } +qreal Chart::distance(const QPointF &p1, const QPointF &p2) +{ + return sqrt((p1.x() - p2.x()) * (p1.x() - p2.x()) + + (p1.y() - p2.y()) * (p1.y() - p2.y())); +} + void Chart::setPointClicked(bool clicked) { m_clicked = clicked; diff --git a/demos/chartinteractions/chart.h b/demos/chartinteractions/chart.h index f9e021a..242aa65 100644 --- a/demos/chartinteractions/chart.h +++ b/demos/chartinteractions/chart.h @@ -41,6 +41,7 @@ public: void setPointClicked(bool clicked); private: + qreal distance(const QPointF &p1, const QPointF &p2); QLineSeries *m_series; QPointF m_movingPoint; diff --git a/demos/chartinteractions/main.cpp b/demos/chartinteractions/main.cpp index 22ab027..7b5db6c 100644 --- a/demos/chartinteractions/main.cpp +++ b/demos/chartinteractions/main.cpp @@ -46,6 +46,9 @@ int main(int argc, char *argv[]) Chart* chart = new Chart(0, 0, series); chart->legend()->hide(); chart->addSeries(series); + QPen p = series->pen(); + p.setWidth(5); + series->setPen(p); chart->createDefaultAxes(); chart->setTitle("Drag'n drop to move data points"); diff --git a/src/linechart/linechartitem.cpp b/src/linechart/linechartitem.cpp index dba8ffd..f52b115 100644 --- a/src/linechart/linechartitem.cpp +++ b/src/linechart/linechartitem.cpp @@ -25,10 +25,9 @@ #include #include - QTCOMMERCIALCHART_BEGIN_NAMESPACE -//TODO: optimize : remove points which are not visible +const qreal mouseEventMinWidth(14); LineChartItem::LineChartItem(QLineSeries* series,ChartPresenter *presenter): XYChart(series, presenter), @@ -49,7 +48,13 @@ QRectF LineChartItem::boundingRect() const QPainterPath LineChartItem::shape() const { - return m_path; + // Increase the size of the path slightly to make mouse interactions more natural + QPainterPathStroker s; + s.setCapStyle(Qt::RoundCap); + s.setJoinStyle(Qt::RoundJoin); + qreal spacing = qMax(mouseEventMinWidth, (qreal) m_linePen.width()); + s.setWidth(spacing); + return s.createStroke(m_path); } void LineChartItem::updateGeometry() @@ -71,8 +76,18 @@ void LineChartItem::updateGeometry() } prepareGeometryChange(); + m_path = linePath; - m_rect = linePath.boundingRect(); + + // When defining bounding rectangle, + // 1. take the line width into account (otherwise you will get drawing artifacts) and + // 2. take the shape into account (otherwise you will not get mouse events through on border + // areas). + const qreal sqrtOf2 = 1.414214; + const qreal spacing = qMax(mouseEventMinWidth / 2.0, + sqrtOf2 * (qreal) m_linePen.width() / 2.0); + m_rect = m_path.boundingRect().adjusted(-spacing, -spacing, spacing, spacing); + setPos(origin()); } @@ -86,8 +101,6 @@ void LineChartItem::handleUpdated() update(); } -//painter - void LineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(widget) diff --git a/src/linechart/linechartitem_p.h b/src/linechart/linechartitem_p.h index 0907104..fee7758 100644 --- a/src/linechart/linechartitem_p.h +++ b/src/linechart/linechartitem_p.h @@ -45,7 +45,7 @@ class LineChartItem : public XYChart , public QGraphicsItem Q_INTERFACES(QGraphicsItem) public: explicit LineChartItem(QLineSeries *series,ChartPresenter *presenter); - ~LineChartItem() {}; + ~LineChartItem() {} //from QGraphicsItem QRectF boundingRect() const;