From 4eee071cd5a1f4c17b0f100776607b082ceab1b8 2012-03-12 16:15:32 From: Michal Klocek Date: 2012-03-12 16:15:32 Subject: [PATCH] Adds missing scatter intercation implementation * adds Marker decorator to track points * tune up scatter interaction example * remove not inplemented marker types from list * bufix xyseries model , handle points with same x value and diffrent y value --- diff --git a/examples/scatterinteractions/mainwindow.cpp b/examples/scatterinteractions/mainwindow.cpp index 5655003..cf2e325 100644 --- a/examples/scatterinteractions/mainwindow.cpp +++ b/examples/scatterinteractions/mainwindow.cpp @@ -1,6 +1,7 @@ #include "mainwindow.h" #include #include +#include #include QTCOMMERCIALCHART_USE_NAMESPACE @@ -9,7 +10,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { QChartView *chartView = new QChartView(this); - chartView->setChartTitle("Click to play with points"); + chartView->setChartTitle("Click to remove scatter point"); chartView->setRenderHint(QPainter::Antialiasing); setCentralWidget(chartView); @@ -19,33 +20,19 @@ MainWindow::MainWindow(QWidget *parent) *m_scatter << QPointF(x, y); } } - chartView->addSeries(m_scatter); - // Add two more series - m_scatter2 = new QScatterSeries(); - chartView->addSeries(m_scatter2); - m_scatter3 = new QScatterSeries(); - chartView->addSeries(m_scatter3); + chartView->addSeries(m_scatter); + chartView->axisX()->setRange(0,4.5); + chartView->axisY()->setRange(0,4.5); - connect(m_scatter, SIGNAL(clicked(QPointF)), this, SLOT(clickPoint(QPointF))); + connect(m_scatter, SIGNAL(clicked(const QPointF&)), this, SLOT(handleClickedPoint(const QPointF&))); } MainWindow::~MainWindow() { } -void MainWindow::clickPoint(QPointF coordinate) +void MainWindow::handleClickedPoint(const QPointF& point) { - // Remove the clicked point from the series and add points to the two other series we have - //TODO: fix me - /* - int index = m_scatter->closestPoint(coordinate); - QPointF point = m_scatter->data().at(index); - Q_ASSERT(m_scatter->removeAt(index)); - point.rx() += 0.25; - point.ry() += 0.25; - *m_scatter2 << point; - point.ry() -= 0.25; - *m_scatter3 << point; - */ + m_scatter->remove(point); } diff --git a/examples/scatterinteractions/mainwindow.h b/examples/scatterinteractions/mainwindow.h index fb71277..080d3ef 100644 --- a/examples/scatterinteractions/mainwindow.h +++ b/examples/scatterinteractions/mainwindow.h @@ -16,7 +16,7 @@ public: ~MainWindow(); private Q_SLOTS: - void clickPoint(QPointF coordinate); + void handleClickedPoint(const QPointF& point); private: QScatterSeries *m_scatter; diff --git a/src/charttheme.cpp b/src/charttheme.cpp index 5844100..e534f2c 100644 --- a/src/charttheme.cpp +++ b/src/charttheme.cpp @@ -169,13 +169,19 @@ void ChartTheme::decorate(ScatterChartItem* item, QScatterSeries* series, int in Q_ASSERT(item); Q_ASSERT(series); - // Use a base color for brush - item->setBrush(m_seriesColors.at(index % m_seriesColors.size())); + QPen pen; + QBrush brush; + + if (pen == series->pen()) { + pen.setColor(colorAt(m_seriesGradients.at(count % m_seriesGradients.size()), 1.0)); + pen.setWidthF(2); + series->setPen(pen); + } - // Take pen near from gradient start, effectively using a lighter color for outline - QPen pen(QBrush(Qt::SolidPattern), 3); - pen.setColor(colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 1.0)); - item->setPen(pen); + if (brush == series->brush()) { + QBrush brush(m_seriesColors.at(count % m_seriesColors.size())); + series->setBrush(brush); + } } void ChartTheme::decorate(PiePresenter* item, QPieSeries* series, int index) diff --git a/src/scatterseries/qscatterseries.cpp b/src/scatterseries/qscatterseries.cpp index a2a3c9a..feb2fc7 100644 --- a/src/scatterseries/qscatterseries.cpp +++ b/src/scatterseries/qscatterseries.cpp @@ -27,13 +27,8 @@ This enum describes the shape used when rendering marker items. - \value MarkerShapeDefault - \value MarkerShapeX - \value MarkerShapeRectangle - \value MarkerShapeRoundedRectangle - \value MarkerShapeTiltedRectangle - \value MarkerShapeTriangle \value MarkerShapeCircle + \value MarkerShapeRectangle */ /*! @@ -54,7 +49,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE */ QScatterSeries::QScatterSeries(QObject *parent) : QXYSeries(parent), - m_shape(QScatterSeries::MarkerShapeDefault), + m_shape(QScatterSeries::MarkerShapeCircle), m_size(9.0) { } diff --git a/src/scatterseries/qscatterseries.h b/src/scatterseries/qscatterseries.h index 57f4a24..98fa178 100644 --- a/src/scatterseries/qscatterseries.h +++ b/src/scatterseries/qscatterseries.h @@ -15,15 +15,8 @@ class QTCOMMERCIALCHART_EXPORT QScatterSeries : public QXYSeries public: enum MarkerShape { - // TODO: to be defined by the graphics design - // TODO: marker shapes: "x", star, rectangle, tilted rect, triangle, circle, dot - MarkerShapeDefault = 0, - MarkerShapeX, - MarkerShapeRectangle, - MarkerShapeRoundedRectangle, - MarkerShapeTiltedRectangle, - MarkerShapeTriangle, - MarkerShapeCircle + MarkerShapeCircle, + MarkerShapeRectangle }; public: diff --git a/src/scatterseries/scatterchartitem.cpp b/src/scatterseries/scatterchartitem.cpp index 44f95cc..5279af1 100644 --- a/src/scatterseries/scatterchartitem.cpp +++ b/src/scatterseries/scatterchartitem.cpp @@ -23,7 +23,8 @@ ScatterChartItem::ScatterChartItem(QScatterSeries *series, QGraphicsItem *parent Q_ASSERT(parent); Q_ASSERT(series); - connect(m_series,SIGNAL(updated()), this, SLOT(handleUpdated())); + QObject::connect(m_series,SIGNAL(updated()), this, SLOT(handleUpdated())); + QObject::connect(this,SIGNAL(clicked(const QPointF&)), m_series, SIGNAL(clicked(const QPointF&))); setZValue(ChartPresenter::ScatterSeriesZValue); setFlags(QGraphicsItem::ItemHasNoContents); @@ -31,6 +32,8 @@ ScatterChartItem::ScatterChartItem(QScatterSeries *series, QGraphicsItem *parent handleUpdated(); + m_items.setHandlesChildEvents(false); + // TODO: how to draw a drop shadow? // QGraphicsDropShadowEffect *dropShadow = new QGraphicsDropShadowEffect(); // dropShadow->setOffset(2.0); @@ -51,27 +54,23 @@ void ScatterChartItem::createPoints(int count) QGraphicsItem *item; switch (m_shape) { - case QScatterSeries::MarkerShapeDefault: - // Fallthrough, defaults to circle - case QScatterSeries::MarkerShapeCircle: - item = new QGraphicsEllipseItem(0,0,m_size,m_size); - break; - case QScatterSeries::MarkerShapeRectangle: - item = new QGraphicsRectItem(0,0,m_size,m_size); + case QScatterSeries::MarkerShapeCircle:{ + QGraphicsEllipseItem* i = new QGraphicsEllipseItem(0,0,m_size,m_size); + const QRectF& rect = i->boundingRect(); + i->setPos(-rect.width()/2,-rect.height()/2); + item = new Marker(i,this); break; - case QScatterSeries::MarkerShapeRoundedRectangle: - //m_path.addRoundedRect(x, y, size, size, size / 4.0, size / 4.0); + } + case QScatterSeries::MarkerShapeRectangle:{ + QGraphicsRectItem* i = new QGraphicsRectItem(0,0,m_size,m_size); + i->setPos(-m_size/2,-m_size/2); + item = new Marker(i,this); break; - case QScatterSeries::MarkerShapeTiltedRectangle: - // TODO: tilt the rectangle - //m_path.addRect(x, y, size, size); - //break; - case QScatterSeries::MarkerShapeTriangle: - //QPolygonF polygon; - //polygon << QPointF(0.0, -size) << QPointF(size / 2.0, 0.0) << QPointF(-size / 2, 0.0); - // TODO: the position is not exactly right... - //m_path.addPolygon(polygon.translated(x + size / 2.0, y + size)); + } + default: + qWarning()<<"Unsupported marker type"; break; + } m_items.addToGroup(item); } @@ -86,18 +85,10 @@ void ScatterChartItem::deletePoints(int count) } } -/* - -void ScatterChartItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +void ScatterChartItem::markerSelected(Marker* marker) { - - QPointF clickedPoint( - m_minX + (event->lastPos().x() / m_clippingRect.width()) * (m_maxX-m_minX), - m_maxY - (event->lastPos().y() / m_clippingRect.height()) * (m_maxY-m_minY)); - emit clicked(clickedPoint); - + emit clicked(QPointF(m_series->x(marker->index()), m_series->y(marker->index()))); } -*/ void ScatterChartItem::setGeometry(QVector& points) { @@ -117,9 +108,10 @@ void ScatterChartItem::setGeometry(QVector& points) QList items = m_items.childItems(); for(int i=0; i< points.size();i++) { - QGraphicsItem* item = items.at(i); + Marker* item = static_cast(items.at(i)); const QPointF& point = points.at(i); const QRectF& rect = item->boundingRect(); + item->setIndex(i); item->setPos(point.x()-rect.width()/2,point.y()-rect.height()/2); if(!clipRect().contains(point)) { item->setVisible(false); @@ -145,14 +137,14 @@ void ScatterChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * void ScatterChartItem::setPen(const QPen& pen) { foreach(QGraphicsItem* item , m_items.childItems()) { - static_cast(item)->setPen(pen); + static_cast(item)->setPen(pen); } } void ScatterChartItem::setBrush(const QBrush& brush) { foreach(QGraphicsItem* item , m_items.childItems()) { - static_cast(item)->setBrush(brush); + static_cast(item)->setBrush(brush); } } diff --git a/src/scatterseries/scatterchartitem_p.h b/src/scatterseries/scatterchartitem_p.h index 9c1a39b..5e156ee 100644 --- a/src/scatterseries/scatterchartitem_p.h +++ b/src/scatterseries/scatterchartitem_p.h @@ -9,6 +9,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE class QScatterSeries; +class Marker; class ScatterChartItem : public XYChartItem { @@ -24,8 +25,10 @@ public: void setPen(const QPen& pen); void setBrush(const QBrush& brush); + void markerSelected(Marker* item); + signals: - void clicked(QPointF coordinates); + void clicked(const QPointF& point); public slots: void handleUpdated(); @@ -46,6 +49,74 @@ private: }; + +class Marker: public QAbstractGraphicsShapeItem +{ + +public: + + Marker(QAbstractGraphicsShapeItem* item , ScatterChartItem* parent):QAbstractGraphicsShapeItem(0),m_item(item),m_parent(parent) + { + }; + + ~Marker() + { + delete m_item; + } + + void setIndex(int index) + { + m_index=index; + } + + int index() const + { + return m_index; + } + + QPainterPath shape() const + { + return m_item->shape(); + } + + QRectF boundingRect() const + { + return m_item->boundingRect(); + } + + bool contains(const QPointF &point) const + { + return m_item->contains(point); + } + + void setPen(const QPen& pen) + { + m_item->setPen(pen); + } + + void setBrush(const QBrush& brush) + { + m_item->setBrush(brush); + } + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) + { + m_item->paint(painter,option,widget); + } + +protected: + + void mousePressEvent( QGraphicsSceneMouseEvent * event ) + { + m_parent->markerSelected(this); + } + +private: + QAbstractGraphicsShapeItem* m_item; + ScatterChartItem* m_parent; + int m_index; +}; + QTCOMMERCIALCHART_END_NAMESPACE #endif // SCATTERPRESENTER_H diff --git a/src/xychart/qxyseries.cpp b/src/xychart/qxyseries.cpp index 09f666e..40d0ed0 100644 --- a/src/xychart/qxyseries.cpp +++ b/src/xychart/qxyseries.cpp @@ -111,11 +111,16 @@ void QXYSeries::replace(const QPointF& point) } /*! - Removes current \a x and y value. + Removes current \a x and \a y value. */ -void QXYSeries::remove(qreal x) +void QXYSeries::remove(qreal x,qreal y) { - int index = m_x.indexOf(x); + int index =-1; + do{ + index = m_x.indexOf(x,index+1); + }while(index !=-1 && m_y.at(index)!=y); + + if(index==-1) return; emit pointRemoved(index); m_x.remove(index); m_y.remove(index); @@ -126,7 +131,7 @@ void QXYSeries::remove(qreal x) */ void QXYSeries::remove(const QPointF& point) { - remove(point.x()); + remove(point.x(),point.y()); } /*! diff --git a/src/xychart/qxyseries.h b/src/xychart/qxyseries.h index 25fb837..f8e48cc 100644 --- a/src/xychart/qxyseries.h +++ b/src/xychart/qxyseries.h @@ -22,7 +22,7 @@ public: void add(const QList points); void replace(qreal x,qreal y); void replace(const QPointF& point); - void remove(qreal x); + void remove(qreal x, qreal y); void remove(const QPointF& point); void removeAll();