QGraphicsScene item is drawn at twice(x2) position
-
In the following code I am creating a custom widget which has a subclass of QGraphicsScene embeded in it. My aim is to click and add a point to the scene. A point is my subclass of QGraphicsItem. I want to move that point around and later connect it to other points and make a spline path. The problem I am facing is that the point is not drawn at where I click but at a place which is form by doubling the mouse-event's scenePos() coordinates. So if I click at (100,100) the point is drawn at (200,200). I suspect that I have misunderstood the coordinate system despite reading the documentation. So I am asking additionally to point me to some simple-to-digest advice on how the widgets placement works. My example code follows:
/* use the following pro: QT += widgets core gui CONFIG += debug console SOURCES = example.cpp TARGET = example */ #include <QGraphicsItem> #include <QPainter> #include <QWidget> #include <QRectF> #include <QPointF> #include <QGraphicsScene> #include <QStyleOptionGraphicsItem> #include <QGraphicsSceneMouseEvent> #include <QKeyEvent> #include <QGraphicsView> #include <QApplication> #include <QOpenGLWidget> #include <QMainWindow> #include <QGridLayout> #include <QDebug> class GIPoint : public QGraphicsItem{ public: GIPoint(QGraphicsItem * parent, const QPointF &position); protected: QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override; QRectF boundingRect() const override; void paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget ); }; class GraphicsSceneWidget : public QGraphicsScene { public: explicit GraphicsSceneWidget(QObject *parent); ~GraphicsSceneWidget(); virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); }; class VectorGraphicsWidget : public QWidget { public: VectorGraphicsWidget(QWidget *parent); ~VectorGraphicsWidget(); private: GraphicsSceneWidget *myGraphicsSceneWidget; }; // implementation GIPoint::GIPoint( QGraphicsItem *parent, const QPointF &position ) : QGraphicsItem(parent) { setFlag(QGraphicsItem::ItemIsMovable, true); setFlag(QGraphicsItem::ItemIsSelectable, true); setPos(position); qWarning() << "GIPoint::GIPoint() : init at " << position; } QVariant GIPoint::itemChange( GraphicsItemChange change, const QVariant &value ){ if (change == QGraphicsItem::ItemPositionChange) { qWarning("position changed"); } return value; } QRectF GIPoint::boundingRect() const { return QRectF(pos().x(), pos().y(), 5, 5); // return QRectF(0,0, 5, 5); } void GIPoint::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget ){ (void )option; (void )widget; QPointF xx = scenePos(); QRectF rect = QRectF(xx.x(), xx.y(), 10, 10); qWarning() << "painting: scenePos " << scenePos() << ", rect " << rect; QBrush brush = QBrush(Qt::black, Qt::SolidPattern); //painter->fillRect(rect, brush); painter->drawRect(rect); } GraphicsSceneWidget::GraphicsSceneWidget(QObject *parent) : QGraphicsScene(parent) {} GraphicsSceneWidget::~GraphicsSceneWidget(){} void GraphicsSceneWidget::mousePressEvent( QGraphicsSceneMouseEvent *event ){ GIPoint *gip = new GIPoint(Q_NULLPTR, event->scenePos()); addItem(gip); QGraphicsScene::mousePressEvent(event); } VectorGraphicsWidget::VectorGraphicsWidget(QWidget *parent) : QWidget(parent) { myGraphicsSceneWidget = new GraphicsSceneWidget(this); QGraphicsView *view = new QGraphicsView(myGraphicsSceneWidget); myGraphicsSceneWidget->setSceneRect(QRectF(0, 0, 500, 500)); QGridLayout *centralLayout = new QGridLayout; centralLayout->addWidget(view); setLayout(centralLayout); myGraphicsSceneWidget->addRect( QRectF(0, 0, 100, 100), QPen(Qt::black), QBrush(Qt::green) ); view->show(); } VectorGraphicsWidget::~VectorGraphicsWidget() { delete myGraphicsSceneWidget; } int main(int argc, char **argv){ QApplication app(argc, argv); app.setApplicationName("test"); app.setOrganizationName("myorg"); app.setOrganizationDomain("myorg.com"); QMainWindow *w = new QMainWindow(); w->resize(500, 500); w->setCentralWidget(new VectorGraphicsWidget(Q_NULLPTR)); w->show(); return app.exec(); }
-
I have just figured it out.
My first misunderstanding was that the boundingRect()'s coordinates must be (-0.5,-0.5) which means they are relative to the current item's position and not absolute on the Scene. and so this is the correct one:
QRectF GIPoint::boundingRect() const { // return QRectF(pos().x(), pos().y(), 5, 5); return QRectF(-0.5, -0.5, 5, 5); }
My second misunderstanding was in
paint()
. Do not use thepos()
orscenePos()
coordinates in order to draw the item. Instead draw it at (0,0). So the correctedpaint()
is this:void GIPoint::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget ){ (void )option; (void )widget; QRectF rect = boundingRect(); qWarning() << "painting: scenePos " << scenePos() << ", rect " << rect; QBrush brush = QBrush(Qt::black, Qt::SolidPattern); painter->fillRect(rect, brush); //painter->drawRect(rect); }
The original program in my question still needs to be modified. Or shall I edit the changes in?
-
I have just figured it out.
My first misunderstanding was that the boundingRect()'s coordinates must be (-0.5,-0.5) which means they are relative to the current item's position and not absolute on the Scene. and so this is the correct one:
QRectF GIPoint::boundingRect() const { // return QRectF(pos().x(), pos().y(), 5, 5); return QRectF(-0.5, -0.5, 5, 5); }
My second misunderstanding was in
paint()
. Do not use thepos()
orscenePos()
coordinates in order to draw the item. Instead draw it at (0,0). So the correctedpaint()
is this:void GIPoint::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget ){ (void )option; (void )widget; QRectF rect = boundingRect(); qWarning() << "painting: scenePos " << scenePos() << ", rect " << rect; QBrush brush = QBrush(Qt::black, Qt::SolidPattern); painter->fillRect(rect, brush); //painter->drawRect(rect); }
The original program in my question still needs to be modified. Or shall I edit the changes in?