Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. PLEASE help: QGraphicsItem sceneboundingrect() is not under Cursor?!

PLEASE help: QGraphicsItem sceneboundingrect() is not under Cursor?!

Scheduled Pinned Locked Moved Unsolved General and Desktop
qgraphicsscaleqt c++qgraphicssceneqgraphicsitem
5 Posts 2 Posters 285 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    StudentScripter
    wrote on last edited by
    #1

    So i subclassed qgraphicsrectitem and added a scaletransform but why the heck is the sceneboundingrect() moved all over the place when moving the qgraphicsrectitem? The rect() however is displayed on the correct dragged position.

    ResizablePixmapItem::ResizablePixmapItem(QPixmap pixmap) :
        mPixmap(pixmap)
    {
    
        setAcceptDrops(true);
        setFlags(QGraphicsRectItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable));
    
    
        setRect(0,0,100,100);
    
        QGraphicsScale *scaletrans = new QGraphicsScale();
    
        scaletrans->setOrigin(QVector3D(sceneBoundingRect().x(), sceneBoundingRect().y(), 0.0));
        scaletrans->setXScale(1.5);
        scaletrans->setYScale(1.5);
    
        this->setTransformations({scaletrans});
    
    }
    
    
    
    
    
    
    
    void ResizablePixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
    {
        Q_UNUSED(option);
        Q_UNUSED(widget);
    
    
        painter->setRenderHints(QPainter::Antialiasing | QPainter::LosslessImageRendering | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
    
    
        painter->setPen(Qt::black);
          painter->setBrush(QBrush(Qt::gray));
          painter->drawRect(sceneBoundingRect());
    
          painter->setBrush(QBrush(Qt::red));
        painter->setPen(QPen(Qt::magenta));
        painter->drawRect(rect());
    
    
        painter->setPen(QPen(Qt::white, 5));
        painter->drawPoint(sceneBoundingRect().topLeft());
    
    
    
        QGraphicsRectItem::paint(painter, option, widget);
    
        this->scene()->update();
    }
    

    And the scene:

    #include "mainwindow.h"
    
    #include <QGraphicsScene>
    #include <QGraphicsView>
    #include "resizablepixmapitem.h"
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
    {
    
        QGraphicsView *view = new QGraphicsView();
    
        QGraphicsScene *scene = new QGraphicsScene();
        scene->setSceneRect(0,0,900,900);
    
        view->setScene(scene);
    
        setCentralWidget(view);
    
    
        QGraphicsRectItem *background = new QGraphicsRectItem(scene->sceneRect());
        background->setBrush(Qt::blue);
        scene->addItem(background);
    
        ResizablePixmapItem *item = new ResizablePixmapItem(QPixmap());
    
        scene->addItem(item);
    
    
    }
    
    MainWindow::~MainWindow() {}
    
    

    This is on startup:
    9a6cad8f-0c43-4088-9df5-9a977491ef08-image.png

    After i moved the rect: (red is the rect() , gray is the sceneboundingrect())
    c0efdde2-8437-442b-a60b-5baee786be8f-image.png

    JonBJ 1 Reply Last reply
    0
    • S StudentScripter

      So i subclassed qgraphicsrectitem and added a scaletransform but why the heck is the sceneboundingrect() moved all over the place when moving the qgraphicsrectitem? The rect() however is displayed on the correct dragged position.

      ResizablePixmapItem::ResizablePixmapItem(QPixmap pixmap) :
          mPixmap(pixmap)
      {
      
          setAcceptDrops(true);
          setFlags(QGraphicsRectItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable));
      
      
          setRect(0,0,100,100);
      
          QGraphicsScale *scaletrans = new QGraphicsScale();
      
          scaletrans->setOrigin(QVector3D(sceneBoundingRect().x(), sceneBoundingRect().y(), 0.0));
          scaletrans->setXScale(1.5);
          scaletrans->setYScale(1.5);
      
          this->setTransformations({scaletrans});
      
      }
      
      
      
      
      
      
      
      void ResizablePixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
      {
          Q_UNUSED(option);
          Q_UNUSED(widget);
      
      
          painter->setRenderHints(QPainter::Antialiasing | QPainter::LosslessImageRendering | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
      
      
          painter->setPen(Qt::black);
            painter->setBrush(QBrush(Qt::gray));
            painter->drawRect(sceneBoundingRect());
      
            painter->setBrush(QBrush(Qt::red));
          painter->setPen(QPen(Qt::magenta));
          painter->drawRect(rect());
      
      
          painter->setPen(QPen(Qt::white, 5));
          painter->drawPoint(sceneBoundingRect().topLeft());
      
      
      
          QGraphicsRectItem::paint(painter, option, widget);
      
          this->scene()->update();
      }
      

      And the scene:

      #include "mainwindow.h"
      
      #include <QGraphicsScene>
      #include <QGraphicsView>
      #include "resizablepixmapitem.h"
      
      MainWindow::MainWindow(QWidget *parent)
          : QMainWindow(parent)
      {
      
          QGraphicsView *view = new QGraphicsView();
      
          QGraphicsScene *scene = new QGraphicsScene();
          scene->setSceneRect(0,0,900,900);
      
          view->setScene(scene);
      
          setCentralWidget(view);
      
      
          QGraphicsRectItem *background = new QGraphicsRectItem(scene->sceneRect());
          background->setBrush(Qt::blue);
          scene->addItem(background);
      
          ResizablePixmapItem *item = new ResizablePixmapItem(QPixmap());
      
          scene->addItem(item);
      
      
      }
      
      MainWindow::~MainWindow() {}
      
      

      This is on startup:
      9a6cad8f-0c43-4088-9df5-9a977491ef08-image.png

      After i moved the rect: (red is the rect() , gray is the sceneboundingrect())
      c0efdde2-8437-442b-a60b-5baee786be8f-image.png

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by
      #2

      @StudentScripter said in PLEASE help: QGraphicsItem sceneboundingrect() is not under Cursor?!:

      but why the heck is the sceneboundingrect() moved all over the place when moving the qgraphicsrectitem?

      It isn't! It stays where it always is/was. As QGraphicsItem::paint() says:

      This function, which is usually called by QGraphicsView, paints the contents of an item in local coordinates.

      All painting is done in local coordinates.

      But your two references to sceneBoundingRect() are in scene coordinates. You need to map them to local/item coordinates in this method.

      Have a play with my changes to your code:

      void ResizablePixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
      {
          Q_UNUSED(option);
          Q_UNUSED(widget);
      
          painter->setRenderHints(QPainter::Antialiasing | QPainter::LosslessImageRendering | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
      
          painter->setPen(Qt::black);
          painter->setBrush(QBrush(Qt::gray));
      
          qDebug() << "sceneBoundingRect" << sceneBoundingRect() << "mapFromScene" << mapFromScene(sceneBoundingRect()).boundingRect();
          painter->drawRect(mapFromScene(sceneBoundingRect()).boundingRect());
      
          QRectF itemRect(rect());
          itemRect -= QMarginsF(10,10,10,10);
          painter->setBrush(QBrush(Qt::red));
          painter->setPen(QPen(Qt::magenta));
          painter->drawRect(itemRect);
      
          painter->setPen(QPen(Qt::white, 5));
          painter->drawPoint(mapFromScene(sceneBoundingRect().topLeft()));
      
          QGraphicsRectItem::paint(painter, option, widget);
      
          this->scene()->update();
      }
      

      I think that's right. You can certainly see the sceneRect() does not change per the qDebug().

      Separately from this, you are not supposed to draw outside a QGraphicsItem::boundingRect() inside QGraphicsItem::paint()

      Make sure to constrain all painting inside the boundaries of boundingRect() to avoid rendering artifacts (as QGraphicsView does not clip the painter for you)

      S 1 Reply Last reply
      3
      • JonBJ JonB

        @StudentScripter said in PLEASE help: QGraphicsItem sceneboundingrect() is not under Cursor?!:

        but why the heck is the sceneboundingrect() moved all over the place when moving the qgraphicsrectitem?

        It isn't! It stays where it always is/was. As QGraphicsItem::paint() says:

        This function, which is usually called by QGraphicsView, paints the contents of an item in local coordinates.

        All painting is done in local coordinates.

        But your two references to sceneBoundingRect() are in scene coordinates. You need to map them to local/item coordinates in this method.

        Have a play with my changes to your code:

        void ResizablePixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
        {
            Q_UNUSED(option);
            Q_UNUSED(widget);
        
            painter->setRenderHints(QPainter::Antialiasing | QPainter::LosslessImageRendering | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
        
            painter->setPen(Qt::black);
            painter->setBrush(QBrush(Qt::gray));
        
            qDebug() << "sceneBoundingRect" << sceneBoundingRect() << "mapFromScene" << mapFromScene(sceneBoundingRect()).boundingRect();
            painter->drawRect(mapFromScene(sceneBoundingRect()).boundingRect());
        
            QRectF itemRect(rect());
            itemRect -= QMarginsF(10,10,10,10);
            painter->setBrush(QBrush(Qt::red));
            painter->setPen(QPen(Qt::magenta));
            painter->drawRect(itemRect);
        
            painter->setPen(QPen(Qt::white, 5));
            painter->drawPoint(mapFromScene(sceneBoundingRect().topLeft()));
        
            QGraphicsRectItem::paint(painter, option, widget);
        
            this->scene()->update();
        }
        

        I think that's right. You can certainly see the sceneRect() does not change per the qDebug().

        Separately from this, you are not supposed to draw outside a QGraphicsItem::boundingRect() inside QGraphicsItem::paint()

        Make sure to constrain all painting inside the boundaries of boundingRect() to avoid rendering artifacts (as QGraphicsView does not clip the painter for you)

        S Offline
        S Offline
        StudentScripter
        wrote on last edited by
        #3

        @JonB Yes your code seems to be more correct, but whats the point than with calling sceneboundingrect() when you have to map it back to local coordinates anyway? (Sorry if thats a dump question)

        But is this fine? Or am i supposed to map it here too?

            QGraphicsScale *scaletrans = new QGraphicsScale();
        
            scaletrans->setOrigin(QVector3D(sceneBoundingRect().x(), sceneBoundingRect().y(), 0.0));
            scaletrans->setXScale(3);
            scaletrans->setYScale(1.5);
        
        
            QGraphicsRotation *rottrans = new QGraphicsRotation();
            rottrans->setOrigin(QVector3D(sceneBoundingRect().center().x(), sceneBoundingRect().center().y(), 0.0));
            rottrans->setAngle(30);
        
            this->setTransformations({rottrans, scaletrans});
        
        JonBJ 1 Reply Last reply
        0
        • S StudentScripter

          @JonB Yes your code seems to be more correct, but whats the point than with calling sceneboundingrect() when you have to map it back to local coordinates anyway? (Sorry if thats a dump question)

          But is this fine? Or am i supposed to map it here too?

              QGraphicsScale *scaletrans = new QGraphicsScale();
          
              scaletrans->setOrigin(QVector3D(sceneBoundingRect().x(), sceneBoundingRect().y(), 0.0));
              scaletrans->setXScale(3);
              scaletrans->setYScale(1.5);
          
          
              QGraphicsRotation *rottrans = new QGraphicsRotation();
              rottrans->setOrigin(QVector3D(sceneBoundingRect().center().x(), sceneBoundingRect().center().y(), 0.0));
              rottrans->setAngle(30);
          
              this->setTransformations({rottrans, scaletrans});
          
          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by
          #4

          @StudentScripter said in PLEASE help: QGraphicsItem sceneboundingrect() is not under Cursor?!:

          whats the point than with calling sceneboundingrect() when you have to map it back to local coordinates anyway?

          You only needed to map it back to locals because of the context you are in, which was inside code for a QGraphicsItem, in its paint() event. And items work in item/"local" coordinates. sceneRect() or sceneBoundingRect() work in scene coordinates. It doesn't make any difference in the end, they convert between each other, you just have to make sure you're using the right ones for whatever task. TBH it's "unusual" to need to go to scene coordinates e.g. inside QGraphicsItem::paint(), you wouldn't normally be interested in the scene or its coordinates there.

          S 1 Reply Last reply
          1
          • JonBJ JonB

            @StudentScripter said in PLEASE help: QGraphicsItem sceneboundingrect() is not under Cursor?!:

            whats the point than with calling sceneboundingrect() when you have to map it back to local coordinates anyway?

            You only needed to map it back to locals because of the context you are in, which was inside code for a QGraphicsItem, in its paint() event. And items work in item/"local" coordinates. sceneRect() or sceneBoundingRect() work in scene coordinates. It doesn't make any difference in the end, they convert between each other, you just have to make sure you're using the right ones for whatever task. TBH it's "unusual" to need to go to scene coordinates e.g. inside QGraphicsItem::paint(), you wouldn't normally be interested in the scene or its coordinates there.

            S Offline
            S Offline
            StudentScripter
            wrote on last edited by StudentScripter
            #5

            @JonB Ok ok but back to the transforms i really get problems with the rectangle shifting when the "setOrigin" changes on the fly. So for example i scale with origin in topleft and scale afterwards with changed origin to topright the item is nudged slightly. I will prepare a minimal reproducable example, but maybe you have an idea just out of the description.

            Edit: And of course big thanks for taking the time.

            1 Reply Last reply
            0

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved