Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QGraphicsItemGroup and childs resize
Qt 6.12 LTS is out! See what's new in the release blog

QGraphicsItemGroup and childs resize

Scheduled Pinned Locked Moved Unsolved General and Desktop
1 Posts 1 Posters 671 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    angeleyes
    wrote on last edited by angeleyes
    #1

    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);
        }
    }
    
    
    1 Reply Last reply
    0
    • Pl45m4P Pl45m4 referenced this topic on

    • Login

    • Login or register to search.
    • First post
      Last post
    0
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Get Qt
    • Unsolved