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 the pos() or scenePos() coordinates in order to draw the item. Instead draw it at (0,0). So the corrected paint() 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?


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.