PLEASE help: QGraphicsItem sceneboundingrect() is not under Cursor?!
-
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:
After i moved the rect: (red is the rect() , gray is the sceneboundingrect())
-
@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 theqDebug()
.Separately from this, you are not supposed to draw outside a
QGraphicsItem::boundingRect()
insideQGraphicsItem::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)
-
@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});
-
@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 itspaint()
event. And items work in item/"local" coordinates.sceneRect()
orsceneBoundingRect()
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. insideQGraphicsItem::paint()
, you wouldn't normally be interested in the scene or its coordinates there. -
@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.