Skip to content
  • 0 Votes
    10 Posts
    469 Views
    Pl45m4P

    @StudentScripter

    The Transformation Example:
    (I modified the default number of 3 sequencial transformations to 5)

    Rotation.png

    As you see, with every rotation the coordinate system (the orientation) of each point of your object (here: the house) changes...
    So also the anchor points have an orientation and a coordinate system... when you change the anchor from, say, bottom-left to top-right, the rotation angle and offset to represent the same pose of the house/your rect also changes.

    You have to break down everything into single operations as soon as you change your anchor and then apply them one after another.

    In the example the anchor is the center of the item.
    [0]-[1]: just shifts/translates by +50 along both axis
    [1]-[2]: rotates house by 60°CW around center
    [2]-[3]: same here
    [3]-[4]: same here
    [4]-[5]: and here

    If you would have changed the anchor (add offset, rotate/apply rot mat, take offset) as you do, you have to sum up ( i.e. multiply matrices) all these operations in the "chain".

    And in between when moving from one anchor to the next, you have to add the translation for the point itself.

    Edit:
    While it is possible to save() and restore() a transformed QPainter (the example above paints the objects directly), the API of QGraphicsItem only allows to set one transformation (setTransform) at a time to scale, shift, rotate the whole thing....
    and this transformation is relative to exactly one origin.
    So starting from the initial origin (0/0) by design, you shift to your inital origin (i.e. bottom-left corner = the anchor point you want to start with).
    To use to chain of multiple and different transformations you need to shift from your current anchor back to the (0/0) point every time (as you do) and pay respect to any possible rotation/translation relative to former anchor points.
    But then from your latest anchor's POV.
    This is why you can't get around solving the "puzzle".

    Search for rotations in R2, R3 (2D, 3D) space with a not fixed(!) object coordinate system (since you move your origin)...
    the "world" coordinate system in where we operate (here the scene coords) stays the same and we rotate along the same axis. However we move the usually fixed object orientation when changing the "anchor".
    Maybe it helps to move this issue to 3D space (it adds one dimension to the vectors and matrices, but I mean for your understanding).

    https://www.youtube.com/watch?v=wg9bI8-Qx2Q

    @Pl45m4 said in QTransform graphicsitems shifting when origin changed:

    For this I think you have to take the offset (distance between those points) and their location (below/above, left/right from center/middle) into consideration... A shift of the origin, a change of the orientation of the axes.

    What I meant here is what is explained in the video... using the "right-hand-rule"...
    When moving the anchor (origin of the object's coordinate system) "just like that", the orientation might change as well (and not only the shift/translation is happening).

  • 0 Votes
    5 Posts
    187 Views
    S

    @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.

  • 0 Votes
    12 Posts
    703 Views
    Pl45m4P

    @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 calling setTopLeft manually will mess up your item and the current transformation completely.

  • 0 Votes
    1 Posts
    237 Views
    No one has replied
  • 0 Votes
    5 Posts
    438 Views
    Q

    @Pl45m4 said in QGraphicsScene and event handling:

    Due to optimization, not the whole scene is redrawn after operation, so if somehow some painted path/region of a (re-)moved or resized item exceeds the boundingRect, this area might not get updated. Therefore remains might stay visible.

    This indeed was one problem. The other one was that despite the call to removeItem(), the item stayed in the BSPTree, because the boundingRect changed without a previous call to prepareGeometryChange() (which I had everywhere except in this hidden case). Clearly my fault! Overall, this is not very fault tolerant and also not easy to debug! In a way, it would be nice to have a function that could be called (during debugging) to do some consistency checking, rather than only finding out much later during a paint event.

  • 0 Votes
    13 Posts
    1k Views
    S

    @Asperamanca Thanks thats a good call, gonna have a look at it. Thanks for the time and effort. <3 Gonna write again here if i encounter other questions regarding this. :D

  • 0 Votes
    11 Posts
    869 Views
    S

    @Pl45m4 Got i solved by just handling the selection in the mousepress and release event. However now im stuck with painting handles to resize the groupitem. I don't really know how to do that as qgraphicsgrouptitem has no setRect method.

    Here is my graphicsgroupitem;

    #include "resizablegraphicsgroupitem.h" #include "qpainter.h" #include <QPen> ResizableGraphicsGroupItem::ResizableGraphicsGroupItem() { // Initialisierungen hier, falls benötigt setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemSendsScenePositionChanges | QGraphicsItem::ItemSendsGeometryChanges); setOwnerItem(this); } QRectF ResizableGraphicsGroupItem::boundingRect() const { return childrenBoundingRect(); } void ResizableGraphicsGroupItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { qDebug() << "Test"; Q_UNUSED(option); Q_UNUSED(widget); painter->save(); //Malt eine Linie um das Rechteck painter->setPen(QPen(Qt::green)); painter->drawRect(boundingRect()); painter->restore(); }

    I coded such a handle class before, but i don't know how to get it to work with a qgraphicsgroupitem:

    #include "resizablehandlerect.h" #include <QGraphicsScene> #include <QDebug> #include <QCursor> ResizableHandleRect::ResizableHandleRect() { } ResizableHandleRect::~ResizableHandleRect() { } void ResizableHandleRect::drawHandles() { qDebug() << "ResizableHandleRect DrawHandles triggered!"; // Erstellen und Hinzufügen der Handles zur Szene //Populate handles in list if(handleList.count() == 0){ handleList.append(new HandleItem(HandleItem::TopLeft)); handleList.append(new HandleItem(HandleItem::TopCenter)); handleList.append(new HandleItem(HandleItem::TopRight)); handleList.append(new HandleItem(HandleItem::RightCenter)); handleList.append(new HandleItem(HandleItem::BottomRight)); handleList.append(new HandleItem(HandleItem::BottomCenter)); handleList.append(new HandleItem(HandleItem::BottomLeft)); handleList.append(new HandleItem(HandleItem::LeftCenter)); } //Set up pen QPen mPen; mPen.setWidth(2); mPen.setColor(Qt::black); //Top left handle QPointF topLeftCorner = selectorFrameBounds().topLeft() + QPointF(-8.0,-8.0); topLeftHandleRect = QRectF(topLeftCorner,QSize(8,8)); handleList[0]->setRect(topLeftHandleRect); if(!handleList.isEmpty() && (!handlesAddedToScene)){ handleList[0]->setPen(mPen); //handleList[0]->setBrush(QBrush(Qt::black)); ownerItem->scene()->addItem(handleList[0]); handleList[0]->setParentItem(ownerItem); handleList[0]->setCursor(Qt::SizeFDiagCursor); } //Top Center QPointF topCenterCorner = QPointF(selectorFrameBounds().left() + selectorFrameBounds().width() / 2.0 - 4.0, selectorFrameBounds().top()-4.0); topCenterHandleRect = QRectF(topCenterCorner,QSize(8,8)); handleList[1]->setRect(topCenterHandleRect); if(!handleList.isEmpty() && (!handlesAddedToScene)){ handleList[1]->setPen(mPen); //handleList[1]->setBrush(QBrush(Qt::gray)); ownerItem->scene()->addItem(handleList[1]); handleList[1]->setParentItem(ownerItem); handleList[1]->setCursor(Qt::SizeVerCursor); } //Top right QPointF topRightCorner = selectorFrameBounds().topRight() + QPointF(0,-8.0); topRightHandleRect = QRectF(topRightCorner,QSize(8,8)); handleList[2]->setRect(topRightHandleRect); if(!handleList.isEmpty() && (!handlesAddedToScene)){ handleList[2]->setPen(mPen); //handleList[1]->setBrush(QBrush(Qt::gray)); ownerItem->scene()->addItem(handleList[2]); handleList[2]->setParentItem(ownerItem); handleList[2]->setCursor(Qt::SizeBDiagCursor); } //Right Center QPointF rightCenterCorner = QPointF(selectorFrameBounds().right() - 4.0, selectorFrameBounds().top() + selectorFrameBounds().height() / 2.0 - 4.0); rightCenterHandleRect = QRectF(rightCenterCorner, QSize(8, 8)); handleList[3]->setRect(rightCenterHandleRect); if (!handleList.isEmpty() && (!handlesAddedToScene)) { handleList[3]->setPen(mPen); ownerItem->scene()->addItem(handleList[3]); handleList[3]->setParentItem(ownerItem); handleList[3]->setCursor(Qt::SizeHorCursor); } //Bottom right QPointF bottomRightCorner = selectorFrameBounds().bottomRight() + QPointF(0,0); bottomRightHandleRect = QRectF(bottomRightCorner,QSize(8,8)); handleList[4]->setRect(bottomRightHandleRect); if(!handleList.isEmpty() && (!handlesAddedToScene)){ handleList[4]->setPen(mPen); //handleList[2]->setBrush(QBrush(Qt::gray)); ownerItem->scene()->addItem(handleList[4]); handleList[4]->setParentItem(ownerItem); handleList[4]->setCursor(Qt::SizeFDiagCursor); } // Bottom Center QPointF bottomCenterCorner = QPointF(selectorFrameBounds().left() + selectorFrameBounds().width() / 2.0 - 4.0, selectorFrameBounds().bottom()-4.0); bottomCenterHandleRect = QRectF(bottomCenterCorner, QSize(8, 8)); handleList[5]->setRect(bottomCenterHandleRect); if (!handleList.isEmpty() && (!handlesAddedToScene)) { handleList[5]->setPen(mPen); ownerItem->scene()->addItem(handleList[5]); handleList[5]->setParentItem(ownerItem); handleList[5]->setCursor(Qt::SizeVerCursor); } //Bottom left QPointF bottomLeftCorner = selectorFrameBounds().bottomLeft() + QPointF(-8,0); bottomLeftHandleRect = QRectF(bottomLeftCorner,QSize(8,8)); handleList[6]->setRect(bottomLeftHandleRect); if(!handleList.isEmpty() && (!handlesAddedToScene)){ handleList[6]->setPen(mPen); //handleList[3]->setBrush(QBrush(Qt::gray)); ownerItem->scene()->addItem(handleList[6]); handleList[6]->setParentItem(ownerItem); handleList[6]->setCursor(Qt::SizeBDiagCursor); } // Left Center QPointF leftCenterCorner = QPointF(selectorFrameBounds().left() - 4.0, selectorFrameBounds().top() + selectorFrameBounds().height() / 2.0 - 4.0); leftCenterHandleRect = QRectF(leftCenterCorner, QSize(8, 8)); handleList[7]->setRect(leftCenterHandleRect); if (!handleList.isEmpty() && (!handlesAddedToScene)) { handleList[7]->setPen(mPen); ownerItem->scene()->addItem(handleList[7]); handleList[7]->setParentItem(ownerItem); handleList[7]->setCursor(Qt::SizeHorCursor); } handlesAddedToScene = true; } void ResizableHandleRect::setOwnerItem(QGraphicsItem *value) { ownerItem = value; } void ResizableHandleRect::drawHandlesIfNecessary(bool ShouldDrawHandles) { qDebug() << "DrawHandles" << ShouldDrawHandles << ownerItem->isSelected(); if(!ownerItem){ qWarning() << "ResizableHandleRect : No ownerItem set. Not drawing any\ handle. Please call setOwnerItem on your ResizableHandleRect subclass"; return; } if(ownerItem->isSelected() && ShouldDrawHandles == true){ drawHandles(); handlesAddedToScene = true; }else if(!ownerItem->isSelected() | (ShouldDrawHandles == false)){ //Remove the handles foreach (HandleItem * handleItem, handleList) { ownerItem->scene()->removeItem(handleItem); } qDeleteAll(handleList); handleList.clear(); handlesAddedToScene = false; } }
  • 1 Votes
    12 Posts
    757 Views
    Chris KawaC

    @JonB said:

    Which I have always regraded as devil's spawn

    Agreed. I see blockSignals() as an advanced tool to be used with great care and only when you're very aware of all consequences in given case. Similar to sender(). Definitely not something to be applied on a "let's see if it helps" basis.

  • 0 Votes
    26 Posts
    4k Views
    SGaistS

    @StudentScripter great !

    Then please mark the model as solved using the "Topic Tools" button or the dotted menu beside the answer you deem correct so that other forum users may know a solution has been found :-)

  • 0 Votes
    2 Posts
    281 Views
    Pl45m4P

    @StudentScripter

    Have you checked the QGraphicsLayout example already?

    https://doc.qt.io/qt-6/qtwidgets-graphicsview-basicgraphicslayouts-example.html
  • 0 Votes
    3 Posts
    327 Views
    JeKK666J

    @JonB Thanks for your feedback :)

  • 0 Votes
    10 Posts
    976 Views
    C

    Hi,

    See if this provides some explanation (read the comments as well):

    StackOverflow: Qt6 QLabel / QPixmap excessive memory usage

  • 0 Votes
    6 Posts
    1k Views
    W

    @JonB I moved my code into QGraphicsView::drawBackground() as you recommended, it works nicely. Thanks a lot!

  • 0 Votes
    5 Posts
    532 Views
    N

    @wrosecrans
    I know that I need them. But don‘t know how to apply them on the scene and keep everything thats on that. I thought that the rect itself has the points in it using the render function of the QGraphicsScene is enough.

    What I do: I set the DragMode of the QGraphicsView to rubberband so the user can select some part pf the scene by simply dragging. The returned rect is now sent to the view to get the underlying image of the scene.

  • 0 Votes
    7 Posts
    1k Views
    SGaistS

    Animation, composition, overlaying and whatever comes to your imagination.

    That said, if you are really only showing one single image and nothing more then, indeed, a QLabel is enough.

  • 0 Votes
    5 Posts
    1k Views
    T

    At the end I've researched again the view's transformations and concluded to support both features and warn for the complexity.

    I did not re-implement the add/remove items of the scene together with a group. Thanks for the hint @Asperamanca .

  • 0 Votes
    3 Posts
    757 Views
    T

    Hey, not sure if you found the solution yet. But you can try this:

    QGraphicsPixmapItem *pixmapItem = new QGraphicsPixmapItem; pixmapItem->setPixmap(QPixmap(":/images/pixmap.png")); _scene->addItem(pixmapItem); pixmapItem->setRotation(pixmapItem->rotation() + 45.0); QGraphicsRectItem *boundingRect = new QGraphicsRectItem(pixmapItem->sceneBoundingRect()); QPen outlinePen; outlinePen.setWidth(2); outlinePen.setColor(Qt::red); boundingRect->setPen(outlinePen); _scene->addItem(boundingRect);

    I believe what you want is the sceneBoundingRect() and not the boundingRect().