Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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 !


  • Lifetime Qt Champion

    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.

    demo.png demo1.png

    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());
    

  • Lifetime Qt Champion

    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.


  • Lifetime Qt Champion

    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 !


  • Lifetime Qt Champion

    @newToQt26
    Heey
    Good work and thank you for sharing :)



  • @mrjj Thank You ! :)


Log in to reply