Skip to content
  • 0 Votes
    9 Posts
    196 Views
    A

    @Deneguil said in Custom QGraphicsEllipseItem mousePressedEvent single clicks:

    @Asperamanca

    Thank you very much for your in depth breakdown of the event propagation pipeline.

    I originally wrote the following line to prevent both events from firing.

    if(itemAt(event->pos()) != nullptr) return;

    Without it it'd print both "GV clicked" and "State clicked".

    If modified it to this one now and it works perfectly.

    if(itemAt(event->pos()) != nullptr) { QGraphics::mousePressEvent(event); return; }

    Both strings are still printed without the return which is why it's still here for apart from that it's perfect.

    Thank you!

    However, this way you are bypassing a lot of things, which could lead to confusion the next time you'd like to add something.

    What you probably want (I'm guessing a bit here) is this:

    void GraphicView::mousePressEvent(QMouseEvent* event) { QGraphicsView::mousePressEvent(event); if(event->isAccepted()) return; std::cout << "GV clicked\n"; }

    Now you can catch the event in the item, handle and accept it.
    The view will know that someone has taken care of the event, and it doesn't need to consider it.

  • 0 Votes
    5 Posts
    132 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
    621 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
    3 Posts
    245 Views
    S

    I tried to debug further but some things i get are just strange. I can't figure out why this happens:

    ORIG TOP LEFT 0 ORIG BOTTOM RIGHT QPointF(450,292) ORIG TOP LEFT 0 ORIG BOTTOM RIGHT QPointF(450,292) ORIG TOP LEFT 0 ORIG BOTTOM RIGHT QPointF(450,250) ORIG TOP LEFT nan ORIG BOTTOM RIGHT QPointF(450,250) ORIG TOP LEFT nan ORIG BOTTOM RIGHT QPointF(450,250) ORIG TOP LEFT nan ORIG BOTTOM RIGHT QPointF(450,250) ORIG TOP LEFT nan ORIG BOTTOM RIGHT QPointF(450,250) ORIG TOP LEFT nan ORIG BOTTOM RIGHT QPointF(450,250)

    Here is the code i get the debbug from:

    #include "handleitem.h" #include "resizablehandlerect.h" #include <QGraphicsSceneMouseEvent> #include <QDebug> #include "resizablepixmapitem.h" HandleItem::HandleItem(Position position) : handlePosition(position) { setFlag(QGraphicsItem::ItemIsMovable); } void HandleItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { ResizableHandleRect *rectItem = dynamic_cast<ResizableHandleRect *>(parentItem()); if (!rectItem) { return; // Wenn das Parent-Item kein ResizableHandleRect ist, beende die Funktion } QRectF boundingFrameRect = rectItem->selectorFrameBounds(); OriginTopLeft = mapToScene(boundingFrameRect.topLeft()); OriginBottomRight = mapToScene(boundingFrameRect.bottomRight()); QRectF SceneBoundingFrameRect(OriginTopLeft, OriginBottomRight); qDebug() << "ORIG TOP LEFT" << OriginLeftCenter << "ORIG BOTTOM RIGHT" << OriginBottomRight; OriginBottomCenter = SceneBoundingFrameRect.bottom(); OriginTopCenter = SceneBoundingFrameRect.top(); BottomCenterWasDragged = false; TopCenterWasDragged = false; } void HandleItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { ResizableHandleRect *rectItem = dynamic_cast<ResizableHandleRect *>(parentItem()); if (!rectItem) { return; // Wenn das Parent-Item kein ResizableHandleRect ist, beende die Funktion } QRectF boundingFrameRect = rectItem->selectorFrameBounds(); QPointF topLeft = mapToScene(boundingFrameRect.topLeft()); QPointF bottomRight = mapToScene(boundingFrameRect.bottomRight()); QRectF SceneBoundingFrameRect(topLeft, bottomRight); //qDebug() << "HandlePosition: " << handlePosition; switch (handlePosition) { case TopLeft: break; case TopCenter: SceneBoundingFrameRect.setTop(event->scenePos().y()); if(SceneBoundingFrameRect.bottom() < SceneBoundingFrameRect.top() && BottomCenterWasDragged == false){ qDebug() << "-- (2)SWITCH Top to Bottom"; handlePosition = BottomCenter; TopCenterWasDragged = true; } break; case TopRight: break; case RightCenter: break; case BottomRight: break; case BottomCenter: SceneBoundingFrameRect.setBottom(event->scenePos().y()); if(SceneBoundingFrameRect.bottom() < SceneBoundingFrameRect.top() && TopCenterWasDragged == false){ qDebug() << "(1)SWITCH Bottom to Top--"; handlePosition = TopCenter; BottomCenterWasDragged = true; } break; case BottomLeft: break; case LeftCenter: break; default: break; } if(SceneBoundingFrameRect.topLeft() != OriginTopLeft && BottomCenterWasDragged == true){ SceneBoundingFrameRect.setTopLeft(OriginTopLeft); BottomCenterWasDragged = false; qDebug() << "(1*)Correct Top, Bottom was Dragged!" << SceneBoundingFrameRect.topLeft(); } if(SceneBoundingFrameRect.bottomRight() != OriginBottomRight && TopCenterWasDragged == true){ SceneBoundingFrameRect.setBottomRight(OriginBottomRight); TopCenterWasDragged = false; qDebug() << "(2*)Correct Bottom, Top was Dragged!" << SceneBoundingFrameRect.bottomRight(); } QPointF topLeft2 = mapFromScene(SceneBoundingFrameRect.topLeft()); QPointF bottomRight2 = mapFromScene(SceneBoundingFrameRect.bottomRight()); QRectF NEWBoundingFrameRect2(topLeft2, bottomRight2); rectItem->setSelectorFrameBounds(NEWBoundingFrameRect2);
  • 0 Votes
    13 Posts
    959 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
    808 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; } }
  • 0 Votes
    2 Posts
    253 Views
    Pl45m4P

    @StudentScripter

    Have you checked the QGraphicsLayout example already?

    https://doc.qt.io/qt-6/qtwidgets-graphicsview-basicgraphicslayouts-example.html
  • 0 Votes
    10 Posts
    913 Views
    C

    Hi,

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

    StackOverflow: Qt6 QLabel / QPixmap excessive memory usage

  • 0 Votes
    5 Posts
    655 Views
    S

    @JonB thanks for googling :) . I have seen some more example. In case of GraphicsView fill transparent on scene did not help. I am pretty sure there is some way to do it, need to google more

  • 0 Votes
    4 Posts
    435 Views
    Pl45m4P

    Either I haven't figured out, what you are doing or it's complete nonsense (esp. the boundingRect)
    Maybe you can add the rest of your code and a screenshot of how your result looks.

    @ugo_ said in How to change cordinate sistem in QGraphicsItem:

    I want to plot my custom item inside a chart.

    Are you talking about QChart? So you have a QChart and want your item in your chart?!

  • 0 Votes
    3 Posts
    428 Views
    W

    @JonB Thanks for your reply! My goal is to draw a filled triangle like this:

    sample3.png

    The only way I'm able to achieve this that I draw two shapes: one fills the whole boundingRect() and a second one draws the outline in boundingRect() adjusted by the pen width.

    I'm not sure that it's a good way to solve this problem. Any tips?

  • 0 Votes
    6 Posts
    571 Views
    W

    @jsulm Thanks!

    @JonB I see, thanks for the clarification!

  • 0 Votes
    3 Posts
    732 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().

  • 0 Votes
    5 Posts
    613 Views
    JonBJ

    @Christian-Ehrlicher said in Collisions with custom QGraphicsItem that inherits from QObject:

    @JonB But it will behave exactly as his class wrt to the pointers:

    Absolutely true! Hence I said

    Apart from the answer @Christian-Ehrlicher has given to the question you ask.

    This is just a suggestion for if OP does want equivalent for the class CustomRect : public QObject, public QGraphicsItem. Not that it will change any behaviour wrt to pointers question.

  • 0 Votes
    5 Posts
    573 Views
    B

    @JonB You’re right, Thanks, QGraphicsItemGroup did the trick. I just needed to set the transform origin point to the centre of the red rectangle. Now the desired effect is achieved by this code:

    #include "game.h" #include <QGraphicsItemGroup> QGraphicsItemGroup* g = new QGraphicsItemGroup; Game::Game() { player = new QGraphicsRectItem(); rectItem = new QGraphicsRectItem(); m_view = new QGraphicsView(this); m_view->setSceneRect(QRectF(0,0,800,600)); this->setBackgroundBrush(Qt::black); m_view->setScene(this); m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_view->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); m_view->setViewportUpdateMode(QGraphicsView::NoViewportUpdate); m_view->show(); player->setRect(0,0,100,100); player->setBrush(Qt::red); player->setPos(400,300); player->setFocus(); rectItem->setRect(0,0,100,100); rectItem->setBrush(Qt::green); rectItem->setPos(400,330); this->addItem(g); player->setZValue(10); rectItem->setZValue(1); g->addToGroup(player); g->addToGroup(rectItem); g->setTransformOriginPoint(player->pos().x() + player->boundingRect().width()/2 ,player->pos().y() + player->boundingRect().height()/2); } void Game::advance() { } void Game::keyPressEvent(QKeyEvent *event) { switch(event->key()) { case Qt::Key_Left : g->moveBy(-5,0); break; case Qt::Key_Right : g->moveBy(5,0); break; case Qt::Key_Up : g->moveBy(0,-5); break; case Qt::Key_Down : g->moveBy(0,5); break; case Qt::Key_Q : g->setRotation(g->rotation()- 3); break; case Qt::Key_W : g->setRotation(g->rotation() +3); break; } update(); }
  • 0 Votes
    34 Posts
    10k Views
    jeremy_kJ

    I guess I provided inadequate subtext for that example. It's documentation in a project I work on, explaining that qObject.signal.connect(lambda: anotherQObject.function(arg)) is unsafe in PyQt if anotherQObject might be destroyed before qObject. The same would happen in C++ with QObject::connect(qObject, &MyClass::signal, [&]() { anotherQObject->function(arg); });

    In C++, one possible solution is to use QObject::Connect(sender, signal, context object, functor). To the best of my knowledge In PyQt5, and I suspect in PySide2/Qt for Python, there is no equivalent. You can write one by taking the connection object returned by object.signal.connect() and using it in a slot connected to anotherQObject.destroyed.