QGraphicsItemGroup and childs resize
-
Hello everybody. I made an algorithm for resizing a picture(inherited from QGraphicsItem) using vector mathematics (I added points to the corners and using the mouse, the picture is resized while maintaining the aspect ratio https://forum.qt.io/topic/124924/qgraphicsitem-resize-with-keeping-aspect-ratio).
Next, I created a group(inherited from QGraphicsItemGroup) add border dots(inherited from QGraphicsRectItem) and added pictures to the group (via addToGroup).
Is it possible to generalize this algorithm to a group? So that all pictures in the group are resized with border dot position.
this what I want: https://gph.is/g/EJxpeVQ
and this is what I got: https://gph.is/g/aQnpq5x
can't resize childs... here the code and gif example:
borderdot.h :#ifndef BORDERDOT_H #define BORDERDOT_H #include <QObject> #include <QGraphicsRectItem> class QGraphicsSceneHoverEventPrivate; class QGraphicsSceneMouseEvent; class DotSignal : public QObject, public QGraphicsRectItem { Q_OBJECT Q_PROPERTY(QPointF previousPosition READ previousPosition WRITE setPreviousPosition NOTIFY previousPositionChanged) public: explicit DotSignal(QGraphicsItem *parentItem = 0, QObject *parent = 0); explicit DotSignal(QPointF pos, QGraphicsItem *parentItem = 0, QObject *parent = 0); ~DotSignal(); enum Flags { Movable = 0x01 }; enum { Type = UserType + 1 }; int type() const override { return Type; } QPointF previousPosition() const; void setPreviousPosition(const QPointF previousPosition); void setDotFlags(unsigned int flags); signals: void previousPositionChanged(); void signalMouseRelease(); void signalMove(QGraphicsItem *signalOwner, qreal dx, qreal dy); protected: void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; void mousePressEvent(QGraphicsSceneMouseEvent *event) override; void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override; void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override; public slots: private: unsigned int m_flags; QPointF m_previousPosition; }; #endif // BORDERDOT_H
borderdot.cpp:
#include "borderdot.h" #include <QBrush> #include <QColor> #include <QGraphicsSceneHoverEvent> #include <QGraphicsSceneMouseEvent> DotSignal::DotSignal(QGraphicsItem *parentItem, QObject *parent) : QObject(parent) { setZValue(999999999); // setFlags(ItemIsMovable); setParentItem(parentItem); setAcceptHoverEvents(true); setBrush(QBrush(Qt::black)); setRect(-4,-4,8,8); setDotFlags(0); } DotSignal::DotSignal(QPointF pos, QGraphicsItem *parentItem, QObject *parent) : QObject(parent) { setZValue(999999999); // setFlags(ItemIsMovable); setParentItem(parentItem); setAcceptHoverEvents(true); setBrush(QBrush(Qt::black)); setRect(-4,-4,8,8); setPos(pos); setPreviousPosition(pos); setDotFlags(0); } DotSignal::~DotSignal() { } QPointF DotSignal::previousPosition() const { return m_previousPosition; } void DotSignal::setPreviousPosition(const QPointF previousPosition) { if (m_previousPosition == previousPosition) return; m_previousPosition = previousPosition; emit previousPositionChanged(); } void DotSignal::setDotFlags(unsigned int flags) { m_flags = flags; } void DotSignal::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if(m_flags & Movable) { qDebug()<<"DotSignal::mouseMoveEvent"; auto dx = event->scenePos().x() - m_previousPosition.x(); auto dy = event->scenePos().y() - m_previousPosition.y(); moveBy(dx,dy); setPreviousPosition(event->scenePos()); emit signalMove(this, dx, dy); } else { qDebug()<<"else DotSignal::mouseMoveEvent"; QGraphicsItem::mouseMoveEvent(event); } } void DotSignal::mousePressEvent(QGraphicsSceneMouseEvent *event) { if(m_flags & Movable){ setPreviousPosition(event->scenePos()); } else { QGraphicsItem::mousePressEvent(event); } } void DotSignal::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { emit signalMouseRelease(); QGraphicsItem::mouseReleaseEvent(event); } void DotSignal::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { qDebug()<<"DotSignal::hoverEnterEvent"; Q_UNUSED(event) setBrush(QBrush(Qt::red)); } void DotSignal::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { qDebug()<<"DotSignal::hoverLeaveEvent"; Q_UNUSED(event) setBrush(QBrush(Qt::black)); }
itemgroup.h:
#ifndef ITEMGROUP_H #define ITEMGROUP_H #include <QObject> #include <QGraphicsItemGroup> class DotSignal; class QGraphicsSceneMouseEvent; class ItemGroup : public QObject, public QGraphicsItemGroup { Q_OBJECT Q_INTERFACES(QGraphicsItem) Q_PROPERTY(QPointF previousPosition READ previousPosition WRITE setPreviousPosition NOTIFY previousPositionChanged) public: enum EItemsType { eBorderDot = QGraphicsItem::UserType + 1, }; ItemGroup(uint64_t& zc, QGraphicsItemGroup *parent = nullptr); ~ItemGroup(); enum ActionStates { ResizeState = 0x01, RotationState = 0x02 }; enum CornerFlags { Top = 0x01, Bottom = 0x02, Left = 0x04, Right = 0x08, TopLeft = Top|Left, TopRight = Top|Right, BottomLeft = Bottom|Left, BottomRight = Bottom|Right }; enum CornerGrabbers { GrabberTop = 0, GrabberBottom, GrabberLeft, GrabberRight, GrabberTopLeft, GrabberTopRight, GrabberBottomLeft, GrabberBottomRight }; public: void addItem(QGraphicsItem* item); void printChilds(); QPointF previousPosition() const; void setPreviousPosition(const QPointF previousPosition); signals: void rectChanged(ItemGroup *rect); void previousPositionChanged(); void clicked(ItemGroup *rect); void signalMove(QGraphicsItemGroup *item, qreal dx, qreal dy); protected: void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; void mousePressEvent(QGraphicsSceneMouseEvent *event) override; void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override; void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override; void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override; void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override; QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; public: void clearItemGroup(); bool isContain(const QGraphicsItem* item) const; bool isEmpty() const; void incZ(); protected: QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; private: QPointF shiftMouseCoords_; uint64_t& zCounter_; QRectF m_tmpRect; private: unsigned int m_cornerFlags; unsigned int m_actionFlags; QPointF m_previousPosition; bool m_leftMouseButtonPressed; DotSignal *cornerGrabber[8]; void resizeLeft( const QPointF &pt); void resizeRight( const QPointF &pt); void resizeBottom(const QPointF &pt); void resizeTop(const QPointF &pt); void rotateItem(const QPointF &pt); void setPositionGrabbers(); void setVisibilityGrabbers(); void hideGrabbers(); }; #endif // ITEMGROUP_H
itemgroup.cpp:
#include <QPainter> #include <QDebug> #include <QCursor> #include <QGraphicsScene> #include <QGraphicsSceneMouseEvent> #include <QGraphicsRectItem> #include <math.h> #include "borderdot.h" static const double Pi = 3.14159265358979323846264338327950288419717; static double TwoPi = 2.0 * Pi; ItemGroup::~ItemGroup() { for(int i = 0; i < 8; i++){ delete cornerGrabber[i]; } } QPointF ItemGroup::previousPosition() const { return m_previousPosition; } void ItemGroup::setPreviousPosition(const QPointF previousPosition) { if (m_previousPosition == previousPosition) return; m_previousPosition = previousPosition; emit previousPositionChanged(); } ItemGroup::ItemGroup(uint64_t& zc, QGraphicsItemGroup *parent) : QGraphicsItemGroup(parent), zCounter_(zc), m_cornerFlags(0), m_actionFlags(ResizeState) { setAcceptHoverEvents(true); setFlags(ItemIsSelectable|ItemSendsGeometryChanges); for(int i = 0; i < 8; i++){ cornerGrabber[i] = new DotSignal(this); } setPositionGrabbers(); } void ItemGroup::addItem(QGraphicsItem* item) { addToGroup(item); auto childs = childItems(); auto tmp = childs.first()->sceneBoundingRect(); for (auto& it : childs) { if (it->type() == eBorderDot) continue; tmp = tmp.united(it->sceneBoundingRect()); } m_tmpRect = tmp; } void ItemGroup::printChilds() { auto childs = childItems(); for (auto& it : childs) { LOG_DEBUG(logger, "CHILDREN: ", it); } } QRectF ItemGroup::boundingRect() const { return m_tmpRect; } void ItemGroup::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { QPointF pt = event->pos(); if(m_actionFlags == ResizeState){ switch (m_cornerFlags) { case Top: resizeTop(pt); break; case Bottom: resizeBottom(pt); break; case Left: resizeLeft(pt); break; case Right: resizeRight(pt); break; case TopLeft: resizeTop(pt); resizeLeft(pt); break; case TopRight: resizeTop(pt); resizeRight(pt); break; case BottomLeft: resizeBottom(pt); resizeLeft(pt); break; case BottomRight: resizeBottom(pt); resizeRight(pt); break; default: if (m_leftMouseButtonPressed) { setCursor(Qt::ClosedHandCursor); auto dx = event->scenePos().x() - m_previousPosition.x(); auto dy = event->scenePos().y() - m_previousPosition.y(); moveBy(dx,dy); setPreviousPosition(event->scenePos()); emit signalMove(this, dx, dy); } break; } } else { if (m_leftMouseButtonPressed) { setCursor(Qt::ClosedHandCursor); auto dx = event->scenePos().x() - m_previousPosition.x(); auto dy = event->scenePos().y() - m_previousPosition.y(); moveBy(dx,dy); setPreviousPosition(event->scenePos()); emit signalMove(this, dx, dy); } } QGraphicsItemGroup::mouseMoveEvent(event); } void ItemGroup::mousePressEvent(QGraphicsSceneMouseEvent *event) { setZValue(++zCounter_); shiftMouseCoords_ = (this->pos() - mapToScene(event->pos()))/scale(); if (event->button() & Qt::LeftButton) { m_leftMouseButtonPressed = true; setPreviousPosition(event->scenePos()); emit clicked(this); } QGraphicsItemGroup::mousePressEvent(event); LOG_DEBUG(logger, "EventPos: (", event->pos().x(),";",event->pos().y(), "), Pos: (", pos().x(),";",pos().y(),")"); } void ItemGroup::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { if (event->button() & Qt::LeftButton) { m_leftMouseButtonPressed = false; } QGraphicsItemGroup::mouseReleaseEvent(event); } void ItemGroup::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { qDebug()<<"ItemGroup::hoverEnterEvent"; setPositionGrabbers(); setVisibilityGrabbers(); QGraphicsItem::hoverEnterEvent(event); } void ItemGroup::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { qDebug()<<"ItemGroup::hoverLeaveEvent"; m_cornerFlags = 0; hideGrabbers(); setCursor(Qt::CrossCursor); QGraphicsItem::hoverLeaveEvent( event ); } void ItemGroup::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { QPointF pt = event->pos(); // The current position of the mouse qreal drx = pt.x() - boundingRect().right(); // Distance between the mouse and the right qreal dlx = pt.x() - boundingRect().left(); // Distance between the mouse and the left qreal dby = pt.y() - boundingRect().top(); // Distance between the mouse and the top qreal dty = pt.y() - boundingRect().bottom(); // Distance between the mouse and the bottom m_cornerFlags = 0; if( dby < 10 && dby > -10 ) m_cornerFlags |= Top; // Top side if( dty < 10 && dty > -10 ) m_cornerFlags |= Bottom; // Bottom side if( drx < 10 && drx > -10 ) m_cornerFlags |= Right; // Right side if( dlx < 10 && dlx > -10 ) m_cornerFlags |= Left; // Left side switch (m_cornerFlags) { case TopLeft: case TopRight: case BottomLeft: case BottomRight: { setCursor(Qt::BusyCursor); break; } default: setCursor(Qt::CrossCursor); break; } } QVariant ItemGroup::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { switch (change) { case QGraphicsItemGroup::ItemSelectedChange: m_actionFlags = ResizeState; break; default: break; } return QGraphicsItemGroup::itemChange(change, value); } void ItemGroup::resizeRight(const QPointF &pt) { QRectF tmpRect = boundingRect(); if( pt.x() < tmpRect.left() ) return; qreal widthOffset = ( pt.x() - tmpRect.left() ); if( widthOffset < 10 ) /// limit return; if( widthOffset < 10) tmpRect.setWidth( -widthOffset ); else tmpRect.setWidth( widthOffset ); prepareGeometryChange(); m_tmpRect = tmpRect; update(); setPositionGrabbers(); } void ItemGroup::resizeTop(const QPointF &pt) { QRectF tmpRect = boundingRect(); if( pt.y() > tmpRect.bottom() ) return; qreal heightOffset = ( pt.y() - tmpRect.bottom() ); if( heightOffset > -11 ) /// limit return; if( heightOffset < 0) tmpRect.setHeight( -heightOffset ); else tmpRect.setHeight( heightOffset ); tmpRect.translate( 0 , boundingRect().height() - tmpRect.height() ); prepareGeometryChange(); m_tmpRect = tmpRect; update(); setPositionGrabbers(); } void ItemGroup::setPositionGrabbers() { QRectF tmpRect = boundingRect(); cornerGrabber[GrabberTop]->setPos(tmpRect.left() + tmpRect.width()/2, tmpRect.top()); cornerGrabber[GrabberBottom]->setPos(tmpRect.left() + tmpRect.width()/2, tmpRect.bottom()); cornerGrabber[GrabberLeft]->setPos(tmpRect.left(), tmpRect.top() + tmpRect.height()/2); cornerGrabber[GrabberRight]->setPos(tmpRect.right(), tmpRect.top() + tmpRect.height()/2); cornerGrabber[GrabberTopLeft]->setPos(tmpRect.topLeft().x(), tmpRect.topLeft().y()); cornerGrabber[GrabberTopRight]->setPos(tmpRect.topRight().x(), tmpRect.topRight().y()); cornerGrabber[GrabberBottomLeft]->setPos(tmpRect.bottomLeft().x(), tmpRect.bottomLeft().y()); cornerGrabber[GrabberBottomRight]->setPos(tmpRect.bottomRight().x(), tmpRect.bottomRight().y()); } void ItemGroup::setVisibilityGrabbers() { cornerGrabber[GrabberTopLeft]->setVisible(true); cornerGrabber[GrabberTopRight]->setVisible(true); cornerGrabber[GrabberBottomLeft]->setVisible(true); cornerGrabber[GrabberBottomRight]->setVisible(true); cornerGrabber[GrabberTop]->setVisible(true); cornerGrabber[GrabberBottom]->setVisible(true); cornerGrabber[GrabberLeft]->setVisible(true); cornerGrabber[GrabberRight]->setVisible(true); } void ItemGroup::hideGrabbers() { for(int i = 0; i < 8; i++){ cornerGrabber[i]->setVisible(false); } }
-