Mapping scene coordinates and Item coordinates
-
Hey everyone !
I do not seem to understand how the coordinate mapping is done. What I want to achieve is restrict my custom QGraphicsRectItem inside sceneRect . I tried doing it with itemChange method . But it doesnot work.
My sceneRect is set as (-800,-400,1600,800) . So when I move my item around , its coordinates(the value stored in QVariant value parameter of itemChange() method) and scene coordinates does not match at all , and as a result the restricting area is entirely different from the sceneRect area.
Also when I draw a rectangle in the middle of the scene , then the restricting area is approximately same as the sceneRect area and both the coordinates match too. How can I get this same behaviour with all the other rectangles drawn anywhere else inside scene?
Can someone help me with whats happening with coordinates?
Thank You ! -
Hi
Are you saying the example form the docs no longer work and wont keep
the item inside scene rect ?
https://doc.qt.io/qt-5/qgraphicsitem.html#itemChange -
@mrjj Hey !
Not really..but doesnot work the way its intended to be.
In both the screenshots , the rectangle's restricting area is entirely different. My scene rect is the middle Rectangle with gridlines. I have zoomed out. both the rectangles should have been restricted inside the sceneRect , but thats not the case.
Is it because I'm setting the rectangle via setRect() method ?This is by dragging :
rectItem->setRect(QRectF(event->scenePos(),QSize(80,50)));
this is using scene Mouse events:
mRect->setRect(QRectF(startingPoint,event->scenePos()).normalized());
-
Hi
but is setRect not in item coordinates ?
In any case does it move the rectangel or does nothing happen ? -
umm nope ! I am setting it in scene coordinates. selecting tool rectangle then the rectangle gets drawn from the the point where mouse was pressed , which becomes topLeft , and the point where mouse was released becomes bottom right , everything in Scene coordinates and scene Mouse Events.
But yeah , rectangle moves fine and even its movements get restricted , but just not inside sceneRect.However , I made some changes to itemChange() . Somebody suggested to do the following changes :
if(!sceneRect.contains(pos)){ pos.setX(qMin(sceneRect.right()-boundingRect().right(), qMax(pos.x(), sceneRect.left()))); pos.setY(qMin(sceneRect.bottom()-boundingRect().bottom(), qMax(pos.y(), sceneRect.top()))); return pos; }
And now , the item's movements are getting limited to just right side of sceneRect and bottom of the sceneRect . I cant do the same for left and top . I tried with the same if statement for the new Point
QPointF newPos = (QPointF(pos.x()+this->rect().width(), pos.y()+this->rect().height()));
But doesnot work.
-
Hi
Did you inspect the values when the rect is in left side then ?
I wonder if its due to left being negative -800, -400 -
@mrjj Hey !
Yes , I did inspect the values. but cant make of it ,because it is in item's coordinate system , and I cant compare it with scene coordinates.
So , according to what I understand , I guess I am making a mistake in itemChange() method. I just adapted it according to documentation and some already existing solutions on internet. I thought by adding the same if condition for newPos point would do the trcik , but I was wrong.
QVariant ResizableRectangle::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { if(change==GraphicsItemChange::ItemPositionChange && scene()) { qDebug()<<"inside itemChange in if"; QRectF sceneRect= this->scene()->sceneRect(); QPointF pos =value.toPointF();; QPointF newPos = (QPointF(pos.x()+this->rect().width(),pos.y()+this->rect().height())); qDebug()<<"pos"<<pos<<"newPos"<<newPos; if(!sceneRect.contains(pos)){ pos.setX(qMin(sceneRect.right()-boundingRect().right(), qMax(pos.x(), sceneRect.left()))); pos.setY(qMin(sceneRect.bottom()-boundingRect().bottom(), qMax(pos.y(), sceneRect.top()))); return pos; } if(!sceneRect.contains(newPos)){ newPos.setX(qMin(sceneRect.right()-boundingRect().right(), qMax(newPos.x(), sceneRect.left()))); newPos.setY(qMin(sceneRect.bottom()-boundingRect().bottom(), qMax(newPos.y(), sceneRect.top()))); return newPos; } } return QGraphicsItem::itemChange(change,value); }
So, I think both these if conditions are checking for Right and Bottom only. But again I am clueless how to do the same for top and left .
-
@mrjj Heyyy !
I figured it out ! I just had to make one small change , subtract boundingRect.left() from sceneRect.left() and subtract boundingRect.right() from sceneRect.right() !
Here is the code , if anyone needs it.
QVariant ResizableRectangle::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { if(change==GraphicsItemChange::ItemPositionChange && scene()) { qDebug()<<"inside itemChange in if"; QRectF sceneRect= this->scene()->sceneRect(); QPointF pos =value.toPointF();; QPointF newPos = QPointF(pos.x()+this->rect().width(),pos.y()+this->rect().height()); qDebug()<<"pos"<<pos<<"newPos"<<newPos; if(!sceneRect.contains(pos)){ pos.setX(qMin(sceneRect.right()-boundingRect().right(), qMax(pos.x(), sceneRect.left()-boundingRect().left()))); pos.setY(qMin(sceneRect.bottom()-boundingRect().bottom(), qMax(pos.y(), sceneRect.top()-boundingRect().top()))); return pos; } if(!sceneRect.contains(newPos)){ newPos.setX(qMin(sceneRect.right()-boundingRect().right(), qMax(newPos.x(), sceneRect.left()-boundingRect().left()))); newPos.setY(qMin(sceneRect.bottom()-boundingRect().bottom(), qMax(newPos.y(), sceneRect.top()-boundingRect().top()))); return newPos; } } return QGraphicsItem::itemChange(change,value); }
@mrjj Thank you so much for replying and being so patient and helping me out !
-
@newToQt26
Heey
Good work and thank you for sharing :)