QGraphicsRectItem item translation instead of movement?
-
I want to do resizing, moving, rotation all as transforms, but is the way i implemented it good, or is there a better solution?
void resizablepixmapitem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { prepareGeometryChange(); QPointF delta = event->scenePos() - event->lastScenePos(); QTransform currentTransform = this->transform(); QTransform translation; translation.translate(delta.x(), delta.y()); setTransform(currentTransform * translation); qreal translationX = transform().m31(); // Translation entlang der X-Achse qreal translationY = transform().m32(); // Translation entlang der Y-Achse qDebug() << "Translation X:" << translationX << "Translation Y:" << translationY; scene()->update(); //QGraphicsRectItem::mouseMoveEvent(event); }
-
@StudentScripter
If it doesn't keep up with fast moving mouse/drag you may want to buffer up some movements, by time. E.g. perhaps once start dragging accumulate moves for say 10th second and then do a single move for multiple little ones. -
Or how to do it best practice? If all should be done by matrix transformations?
-
@StudentScripter
You can manipulate the transform matrix values directly or use the convenience methodsrotate()
etc. in it or callQGraphicsRectItem::setRotation()
etc. methods. Read Transformations..You create a separate
QTransform
for thetranslate()
and then combine that with current transform viacurrentTransform * translation
. You could docurrentTransform.translate(); setTransform(currentTransform);
directly. -
@JonB Thats good, one problem i have with my code using the translation for movement in the scene makes the movement of the object sluggish.
When i drag the graphicsitem normaly with the default method it is smooth and follows the mouse drag 1:1.
But when i try to use translation instead (cause normal moving an rotating messes up the rotation and scaling) it is sluggish and lack behind the mouse when moving fast.Any idea how to fix? I can't be the first person who wants to implement a moveable, resizable and rotatable graphicsitem with handles.
Thanks alot for helping me out. :D
-
@StudentScripter
If it doesn't keep up with fast moving mouse/drag you may want to buffer up some movements, by time. E.g. perhaps once start dragging accumulate moves for say 10th second and then do a single move for multiple little ones. -
@JonB Thanks alot man. Seems to be working, but is having a timer running everytime the item starts to move a good idea? I always thought having a timer inside qgraphicsitem is pretty poor, but maybe im wrong.
Here is an example of my implementation:
ResizablePixmapItem::ResizablePixmapItem(const QPixmap &pixmap, QGraphicsItem *parent) : QGraphicsRectItem{parent}, m_pixmap(pixmap) { setRect(0,0,100,100); setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges | QGraphicsRectItem::ItemSendsScenePositionChanges); MoveTimer = new QTimer(this); connect(MoveTimer, &QTimer::timeout, this, &ResizablePixmapItem::applyBufferedMovement); } void ResizablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { MoveTimer->start(15); QGraphicsRectItem::mousePressEvent(event); } void ResizablePixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if(isSelected() && !handles.empty() && !areHandlesSelected()){ UpdateHandles(); } // Accumulate the movement delta QPointF delta = event->scenePos() - event->lastScenePos(); accumulatedDelta += delta; event->accept(); } void ResizablePixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { MoveTimer->stop(); QGraphicsRectItem::mouseReleaseEvent(event); } void ResizablePixmapItem::applyBufferedMovement() { if (!accumulatedDelta.isNull()) { prepareGeometryChange(); QTransform currentTransform = this->transform(); QTransform translation; translation.translate(accumulatedDelta.x(), accumulatedDelta.y()); setTransform(currentTransform * translation); qreal translationX = transform().m31(); // Translation along the X axis qreal translationY = transform().m32(); // Translation along the Y axis qDebug() << "Buffered Translation X:" << translationX << "Translation Y:" << translationY; scene()->update(); // Update the scene to reflect the movement // Reset the accumulated delta after applying the transformation accumulatedDelta = QPointF(0, 0); } }
-
-
@StudentScripter said in QGraphicsRectItem item translation instead of movement?:
I want to do resizing, moving, rotation all as transforms
I fail to understand the idea of "moving" an item using transformations, when
ItemIsMovable
is set...
Few pixels left and right, top and down, ok granted, but I don't thinkQTranformation
is intended to be used in the way you do.First sentence of Tranformations states:
QGraphicsItem supports projective transformations in addition to its base position, pos().
What you are trying to do, as I understand, is to keep the item at its "base" position and transform it to wherever, in whatever pose, scale, etc.
This is at least what yourmouseMoveEvent
code does (if I'm not mistaken).As setting the movable flag will in addition change the items "base" position... and this might collide with the transformation stuff you are doing... and maybe that's the cause for the misbehavior you describe.
I'm not sure about that, but I don't think you should "tranform" your item across the scene, rather than actually moving it via
setPos()
... or just handle the rotation and scaling, when needed and don't mind the position, as the base implementation triggered byItemIsMovable
will take care of it and find the new position for the item (where it was released and mouse movement stopped). -
@StudentScripter
I agree with @Pl45m4. I don't really know what/why you are doing "translation" when you havesetPos()
,ItemIsMovable
or why you have to do your own work for this. Admittedly I have not written my own stuff for "draggable handles" and with rotation. You say, I think, it "goes wrong", but I don't know why: we think you don't need "translation", can you get rid of that part of your "transformation" and see how it goes? -
@JonB @Pl45m4 Let me explain the problem is the following:
-
I want to apply all transformations e.g. scaling, rotation, translation/moving to my qgraphicsrectitem via a handle class,
--> as i understood it, if you work with these various types of transformations a proper transformation matrix is needed cause moving and scaling should always be happening before rotating -
My before prototype was NOT using proper transformation matrix but setPos()/ItemisMovable instead of translate, rect().setTop, setBottom andsoforth instead of scale transformation, and setRotation --> here i hit the wall where i figured a proper matrix may be need as you can see after scaling the rotation is fucked up and vice verca
(The yellow dot represents the center of the parent/frog image - just for visualizing purpose)
Can't post the code cause it's getting flagged as spam. Can any moderator change this please?
Meanwhile here is a pastebin link to the code: https://pastebin.com/kMDQUtcM -
-
@StudentScripter
I really don't know, I/you would need to play with this graphics item stuff to discover what does/does not work. I believe I read that "rotation goes wrong/unexpected when using scaling at the same time", but that is all I know. I believe there is a further complication that there are two ways to achieve rotation, either viaQTransform::rotate()
or viaQGraphicsItem::setRotation()
. I am unsure whether these are identical. I think there is a difference. Be sure to read https://doc.qt.io/qt-6/qgraphicsitem.html#transformations, including where it lists "QGraphicsItem always applies the properties in a fixed, defined order". -
@JonB Well the real problem seems to be that rect().setTopLeft() and all other direct changes to the parentitems rect result in a changed Origin Point of the object in the scene, while with setScale() the OriginPoint stays intact.
Anyone else does know more about that? @Christian-Ehrlicher @SGaist maybe? -
@StudentScripter said in QGraphicsRectItem item translation instead of movement?:
Well the real problem seems to be that rect().setTopLeft() and all other direct changes to the parentitems rect result in a changed Origin Point of the object in the scene, while with setScale() the OriginPoint stays intact.
AFAIK the "topLeft" of an item rotated by 90° clockwise is still the same point as when not being transformed... the original item stays the same, because you can revert the transformation at any time to get your initial item back. The
QTranform
only "maps" the initial item matrix to your transformed one.
So I think callingsetTopLeft
manually will mess up your item and the current transformation completely.