Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Problem with resizing when object is rotated



  • Hi!
    I have a text-box/rectangle with corner-grabbers to enable to change width & height (draggable corners). But after a rotation/transform the re-size does not works as expected. When dragging the corners I want the oppsite corner to be stucked/not moving as it does when the text-box is not rotated. Please can some have a look at it and give me some advices.

    Best Regards
    Olle

    This function is used to rotate the textbox:

    void StateBox::rotate(qreal angle)
    {
        setTransformOriginPoint(boundingRect().center());
        setRotation(45);
    }
    
    

    textbox rotated.png

    statebox.cpp file:

    #include "statebox.h"
    
    #include <QBrush>
    #include <QLinearGradient>
    #include <QDebug>
    
    #include "math.h"
    
    StateBox::StateBox():
            _text(),
            _outterborderColor(Qt::black),
            _outterborderPen(),
            _location(0,0),
            _dragStart(0,0),
            _gridSpace(10),
            _width(250),
            _height(200),
            _cornerDragStart(0,0),
            _XcornerGrabBuffer(20),
            _YcornerGrabBuffer(20),
            _drawingWidth(  _width -   _XcornerGrabBuffer),
            _drawingHeight( _height -  _YcornerGrabBuffer),
            _drawingOrigenX( _XcornerGrabBuffer),
            _drawingOrigenY( _YcornerGrabBuffer)
    {
    
        _outterborderPen.setWidth(2);
        _outterborderPen.setColor(_outterborderColor);
    
        _text.setPos(35,35);
        _text.setPlainText("text goes here");
        _text.setParentItem(this);
    
        this->setAcceptHoverEvents(true);
    }
    
    void StateBox::adjustSize(int x, int y)
    {
        _width += x;
        _height += y;
        _drawingWidth =  _width - _XcornerGrabBuffer;
        _drawingHeight=  _height - _YcornerGrabBuffer;
    }
    
    bool StateBox::sceneEventFilter ( QGraphicsItem * watched, QEvent * event )
    {
        qDebug() << " QEvent == " + QString::number(event->type());
    
        CornerGrabber * corner = dynamic_cast<CornerGrabber *>(watched);
        if ( corner == NULL) return false; // not expected to get here
    
        QGraphicsSceneMouseEvent * mevent = dynamic_cast<QGraphicsSceneMouseEvent*>(event);
        if ( mevent == NULL)
        {
            // this is not one of the mouse events we are interrested in
            return false;
        }
    
        switch (event->type() )
        {
                // if the mouse went down, record the x,y coords of the press, record it inside the corner object
            case QEvent::GraphicsSceneMousePress:
                {
                    corner->setMouseState(CornerGrabber::kMouseDown);
                    corner->mouseDownX = mevent->pos().x();
                    corner->mouseDownY = mevent->pos().y();
                }
                break;
    
            case QEvent::GraphicsSceneMouseRelease:
                {
                    corner->setMouseState(CornerGrabber::kMouseReleased);
    
                }
                break;
    
            case QEvent::GraphicsSceneMouseMove:
                {
                    corner->setMouseState(CornerGrabber::kMouseMoving );
                }
                break;
    
            default:
                // we dont care about the rest of the events
                return false;
                break;
        }
    
        if ( corner->getMouseState() == CornerGrabber::kMouseMoving )
        {
            qreal x = mevent->pos().x(), y = mevent->pos().y();
    
            // depending on which corner has been grabbed, we want to move the position
            // of the item as it grows/shrinks accordingly. so we need to eitehr add
            // or subtract the offsets based on which corner this is.
    
            int XaxisSign = 0;
            int YaxisSign = 0;
            switch( corner->getCorner() )
            {
            case 0:
                {
                    XaxisSign = +1;
                    YaxisSign = +1;
                }
                break;
    
            case 1:
                {
                    XaxisSign = -1;
                    YaxisSign = +1;
                }
                break;
    
            case 2:
                {
                    XaxisSign = -1;
                    YaxisSign = -1;
                }
                break;
    
            case 3:
                {
                    XaxisSign = +1;
                    YaxisSign = -1;
                }
                break;
    
            }
    
            // if the mouse is being dragged, calculate a new size and also re-position
            // the box to give the appearance of dragging the corner out/in to resize the box
    
            int xMoved = corner->mouseDownX - x;
            int yMoved = corner->mouseDownY - y;
    
            int newWidth = _width + ( XaxisSign * xMoved);
            if ( newWidth < 40 ) newWidth  = 40;
    
            int newHeight = _height + (YaxisSign * yMoved) ;
            if ( newHeight < 40 ) newHeight = 40;
    
            int deltaWidth  =   newWidth - _width ;
            int deltaHeight =   newHeight - _height ;
    
            adjustSize(  deltaWidth ,   deltaHeight);
    
            deltaWidth *= (-1);
            deltaHeight *= (-1);
    
            if ( corner->getCorner() == 0 )
            {
                int newXpos = this->pos().x() + deltaWidth;
                int newYpos = this->pos().y() + deltaHeight;
                this->setPos(newXpos, newYpos);
            }
            else   if ( corner->getCorner() == 1 )
            {
                int newYpos = this->pos().y() + deltaHeight;
                this->setPos(this->pos().x(), newYpos);
            }
            else   if ( corner->getCorner() == 3 )
            {
                int newXpos = this->pos().x() + deltaWidth;
                this->setPos(newXpos,this->pos().y());
            }
    
            setCornerPositions();
    
            this->update();
        }
    
        return true;// true => do not send event to watched - we are finished with this event
    }
    
    // for supporting moving the box across the scene
    void StateBox::mouseReleaseEvent ( QGraphicsSceneMouseEvent * event )
    {
        event->setAccepted(true);
        _location.setX( ( static_cast<int>(_location.x()) / _gridSpace) * _gridSpace );
        _location.setY( ( static_cast<int>(_location.y()) / _gridSpace) * _gridSpace );
        this->setPos(_location);
    }
    
    
    // for supporting moving the box across the scene
    void StateBox::mousePressEvent ( QGraphicsSceneMouseEvent * event )
    {
        event->setAccepted(true);
        _dragStart = event->pos();
    }
    
    
    // for supporting moving the box across the scene
    void StateBox::mouseMoveEvent ( QGraphicsSceneMouseEvent * event )
    {
        QPointF newPos = event->pos() ;
        _location += (newPos - _dragStart);
        this->setPos(_location);
    }
    
    // remove the corner grabbers
    void StateBox::hoverLeaveEvent ( QGraphicsSceneHoverEvent * )
    {
        _outterborderColor = Qt::black;
    
        _corners[0]->setParentItem(NULL);
        _corners[1]->setParentItem(NULL);
        _corners[2]->setParentItem(NULL);
        _corners[3]->setParentItem(NULL);
    
        delete _corners[0];
        delete _corners[1];
        delete _corners[2];
        delete _corners[3];
    }
    
    // create the corner grabbers
    void StateBox::hoverEnterEvent ( QGraphicsSceneHoverEvent * )
    {
        _outterborderColor = Qt::red;
    
        _corners[0] = new CornerGrabber(this,0);
        _corners[1] = new CornerGrabber(this,1);
        _corners[2] = new CornerGrabber(this,2);
        _corners[3] = new CornerGrabber(this,3);
    
    
        _corners[0]->installSceneEventFilter(this);
        _corners[1]->installSceneEventFilter(this);
        _corners[2]->installSceneEventFilter(this);
        _corners[3]->installSceneEventFilter(this);
    
        setCornerPositions();
    
    }
    
    void StateBox::setCornerPositions()
    {
        _corners[0]->setPos(_drawingOrigenX, _drawingOrigenY);
        _corners[1]->setPos(_drawingWidth,  _drawingOrigenY);
        _corners[2]->setPos(_drawingWidth , _drawingHeight);
        _corners[3]->setPos(_drawingOrigenX, _drawingHeight);
    }
    
    QRectF StateBox::boundingRect() const
    {
        return QRectF(0,0,_width,_height);
    }
    
    void StateBox::paint (QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
    {
        int shadowThickness = 3;
    
        QLinearGradient gradient;
        gradient.setStart(_drawingOrigenX,_drawingOrigenY);
        gradient.setFinalStop( _drawingWidth ,_drawingOrigenY);
        QColor grey1(150,150,150,125);// starting color of the gradient - can play with the starting color and ,point since its not visible anyway
    
        // grey2 is ending color of the gradient - this is what will show up as the shadow. the last parameter is the alpha blend, its set
        // to 125 allowing a mix of th color and and the background, making more realistic shadow effect.
        QColor grey2(225,225,225,125);
    
    
        gradient.setColorAt((qreal)0, grey1 );
        gradient.setColorAt((qreal)1, grey2 );
    
        QBrush brush(gradient);
    
        painter->setBrush( brush);
    
        // for the desired effect, no border will be drawn, and because a brush was set, the drawRoundRect will fill the box with the gradient brush.
        _outterborderPen.setStyle(Qt::NoPen);
        painter->setPen(_outterborderPen);
    
        QPointF topLeft (_drawingOrigenX,_drawingOrigenX);
        QPointF bottomRight ( _drawingWidth , _drawingHeight);
    
        QRectF rect (topLeft, bottomRight);
    
        painter->drawRoundRect(rect,25,25); // corner radius of 25 pixels
    
        // draw the top box, the visible one
        QBrush brush2(QColor(243,255,216,255),Qt::SolidPattern);
    
        painter->setBrush( brush2);
    
        QPointF topLeft2 (_drawingOrigenX, _drawingOrigenY);
        QPointF bottomRight2 ( _drawingWidth-shadowThickness, _drawingHeight-shadowThickness);
    
        QRectF rect2 (topLeft2, bottomRight2);
    
        painter->drawRoundRect(rect2,25,25);
    
    }
    
    void StateBox::mouseMoveEvent(QGraphicsSceneDragDropEvent *event)
    {
        event->setAccepted(false);
    }
    
    void StateBox::mousePressEvent(QGraphicsSceneDragDropEvent *event)
    {
        event->setAccepted(false);
    }
    
    void StateBox::rotate(qreal angle)
    {
        setTransformOriginPoint(boundingRect().center());
        setRotation(45);
    }
    

    statebox.h

    #ifndef STATEBOX_H
    #define STATEBOX_H
    
    #include <QGraphicsItem>
    #include <QGraphicsRectItem>
    #include <QGraphicsTextItem>
    #include <QGraphicsSceneHoverEvent>
    #include <QGraphicsSceneMouseEvent>
    #include <QColor>
    #include <QPainter>
    #include <QPen>
    #include <QPointF>
    #include "cornergrabber.h"
    
    class StateBox : public QGraphicsItem
    {
    public:
        StateBox();
        QGraphicsTextItem _text;    ///< sample text to go in the title area.
    
        void setGridSpace(int space);
        void rotate(qreal angle);
    
        private:
    
    
        virtual QRectF boundingRect() const; ///< must be re-implemented in this class to provide the diminsions of the box to the QGraphicsView
        virtual void paint (QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); ///< must be re-implemented here to pain the box on the paint-event
        virtual void hoverEnterEvent ( QGraphicsSceneHoverEvent * event ); ///< must be re-implemented to handle mouse hover enter events
        virtual void hoverLeaveEvent ( QGraphicsSceneHoverEvent * event ); ///< must be re-implemented to handle mouse hover leave events
    
        virtual void mouseMoveEvent ( QGraphicsSceneMouseEvent * event );///< allows the main object to be moved in the scene by capturing the mouse move events
        virtual void mousePressEvent (QGraphicsSceneMouseEvent * event );
        virtual void mouseReleaseEvent (QGraphicsSceneMouseEvent * event );
    
        virtual void mouseMoveEvent(QGraphicsSceneDragDropEvent *event);
        virtual void mousePressEvent(QGraphicsSceneDragDropEvent *event);
        virtual bool sceneEventFilter ( QGraphicsItem * watched, QEvent * event ) ;
    
        void setCornerPositions();
        void adjustSize(int x, int y);
    
    
        QColor _outterborderColor; ///< the hover event handlers will toggle this between red and black
        QPen _outterborderPen; ///< the pen is used to paint the red/black border
        QPointF _location;
        QPointF _dragStart;
        int     _gridSpace;
        qreal   _width;
        qreal   _height;
    
        QPointF _cornerDragStart;
    
        int _XcornerGrabBuffer;
        int _YcornerGrabBuffer;
        qreal   _drawingWidth;
        qreal   _drawingHeight;
        qreal   _drawingOrigenX;
        qreal   _drawingOrigenY;
    
        CornerGrabber*  _corners[4];// 0,1,2,3  - starting at x=0,y=0 and moving clockwise around the box
    };
    
    #endif // STATEBOX_H
    

    cornergrabber.cpp

    #include "cornergrabber.h"
    
    CornerGrabber::CornerGrabber(QGraphicsItem *parent,  int corner) :
        QGraphicsItem(parent),
        mouseDownX(0),
        mouseDownY(0),
        _outterborderColor(Qt::black),
        _outterborderPen(),
        _width(6),
        _height(6),
        _corner(corner),
        _mouseButtonState(kMouseReleased)
    {
        setParentItem(parent);
    
        _outterborderPen.setWidth(2);
        _outterborderPen.setColor(_outterborderColor);
    
       this->setAcceptHoverEvents(true);
    }
    
    void CornerGrabber::setMouseState(int s)
    {
        _mouseButtonState = s;
    }
    
    int CornerGrabber::getMouseState()
    {
        return _mouseButtonState;
    }
    
    int CornerGrabber::getCorner()
    {
        return _corner;
    }
    
    void CornerGrabber::mouseMoveEvent(QGraphicsSceneDragDropEvent *event)
    {
        event->setAccepted(false);
    }
    
    void CornerGrabber::mousePressEvent(QGraphicsSceneDragDropEvent *event)
    {
        event->setAccepted(false);
    }
    
    void CornerGrabber::mouseReleaseEvent ( QGraphicsSceneMouseEvent * event )
    {
        event->setAccepted(true);
    }
    
    void CornerGrabber::mousePressEvent ( QGraphicsSceneMouseEvent * event )
    {
        event->setAccepted(false);
    }
    
    void CornerGrabber::mouseMoveEvent ( QGraphicsSceneMouseEvent * event )
    {
        event->setAccepted(false);
    }
    
    void CornerGrabber::hoverLeaveEvent ( QGraphicsSceneHoverEvent * )
    {
        _outterborderColor = Qt::black;
        this->update(0,0,_width,_height);
    }
    
    void CornerGrabber::hoverEnterEvent ( QGraphicsSceneHoverEvent * )
    {
        _outterborderColor = Qt::red;
        this->update(0,0,_width,_height);
    }
    
    QRectF CornerGrabber::boundingRect() const
    {
        return QRectF(0,0,_width,_height);
    }
    
    void CornerGrabber::paint (QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
    {
        _outterborderPen.setCapStyle(Qt::SquareCap);
        _outterborderPen.setStyle(Qt::SolidLine);
        painter->setPen(_outterborderPen);
    
        QPointF topLeft (0, 0);
        QPointF bottomRight ( _width, _height);
    
        QRectF rect (topLeft, bottomRight);
    
        QBrush brush (Qt::SolidPattern);
        brush.setColor (_outterborderColor);
        painter->fillRect(rect,brush);
    
    }
    
    

    cornergrabber.h

    #ifndef CORNERGRABBER_H
    #define CORNERGRABBER_H
    
    #include <QObject>
    #include <QGraphicsItem>
    #include <QGraphicsRectItem>
    #include <QGraphicsTextItem>
    #include <QGraphicsSceneHoverEvent>
    #include <QGraphicsSceneMouseEvent>
    #include <QColor>
    #include <QPainter>
    #include <QPen>
    #include <QPointF>
    
    class CornerGrabber : public QGraphicsItem
    {
    
    public:
        explicit CornerGrabber(QGraphicsItem *parent = 0,  int corner=0);
    
        int  getCorner(); ///< allows the owner to find out which coner this is
        void setMouseState(int); ///< allows the owner to record the current mouse state
        int  getMouseState(); ///< allows the owner to get the current mouse state
    
        qreal mouseDownX;
        qreal mouseDownY;
    
         enum {kMouseReleased=0, kMouseDown, kMouseMoving}; ///< define the mouse states
    
    private:
    
        virtual QRectF boundingRect() const; ///< must be re-implemented in this class to provide the diminsions of the box to the QGraphicsView
        virtual void paint (QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); ///< must be re-implemented here to pain the box on the paint-event
        virtual void hoverEnterEvent ( QGraphicsSceneHoverEvent * event ); ///< must be re-implemented to handle mouse hover enter events
        virtual void hoverLeaveEvent ( QGraphicsSceneHoverEvent * event ); ///< must be re-implemented to handle mouse hover leave events
        virtual void mouseMoveEvent ( QGraphicsSceneMouseEvent * event );
        virtual void mouseMoveEvent(QGraphicsSceneDragDropEvent *event);
        virtual void mousePressEvent (QGraphicsSceneMouseEvent * event );
        virtual void mousePressEvent(QGraphicsSceneDragDropEvent *event);
        virtual void mouseReleaseEvent (QGraphicsSceneMouseEvent * event );
    
        QColor _outterborderColor; ///< the hover event handlers will toggle this between red and black
        QPen _outterborderPen; ///< the pen is used to paint the red/black border
    
        qreal   _width;
        qreal   _height;
    
        int _corner;// 0,1,2,3  - starting at x=0,y=0 and moving clockwise around the box
        int _mouseButtonState;
    };
    
    #endif // CORNERGRABBER_H
    

    mainwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QDebug>
    #include <QSizePolicy>
    #include <QGraphicsLineItem>
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow()),
        scene( new QGraphicsScene()),
        gview( new QGraphicsView ()),
        stateBox( new StateBox())
    {
        QColor c (242,251,235);
        QBrush brush (c, Qt::SolidPattern);
        scene->setBackgroundBrush(brush);
        ui->setupUi(this);
        ui->horizontalLayout->addWidget( gview);
        stateBox->setPos(200,200);
        stateBox->rotate(45);
        scene->addItem( stateBox);
        gview->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
        gview->setScene(  scene);
        gview->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
        gview->show();
    }
    
    void MainWindow::resizeEvent(QResizeEvent * )
    {
    }
    
    
    MainWindow::~MainWindow()
    {
        delete gview;
        delete stateBox;
        delete scene;
        delete ui;
    }
    

    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    #include <QMainWindow>
    #include <QGraphicsItem>
    #include <QGraphicsScene>
    #include <QGraphicsView>
    #include <QGraphicsEllipseItem>
    #include <QBrush>
    #include <QScrollBar>
    #include <QResizeEvent>
    #include "statebox.h"
    
    namespace Ui
    {
        class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private:
        Ui::MainWindow *ui; ///< QtCreator made this instance.
        QGraphicsScene * scene ; ///< the scene will contain the graphics item 'StateBox'
        QGraphicsView * gview; ///< the graphics view will contain and display the scene.
        StateBox * stateBox; ///< this is my custom QGraphicsItem
    
        virtual void resizeEvent(QResizeEvent *);///< re-implementing this event handler of the QMainWindow class allows my to capture re-size window values - not used in this project
    };
    
    #endif // MAINWINDOW_H
    

    main.cpp

    #include <QtGui/QApplication>
    #include "mainwindow.h"
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
    
        return a.exec();
    }
    

    pro file:

    QT       += core gui
    
    TARGET = GraphicsViewFrameWork_lesson_3
    TEMPLATE = app
    
    
    SOURCES += main.cpp\
            mainwindow.cpp \
        statebox.cpp \
        cornergrabber.cpp
    
    HEADERS  += mainwindow.h \
        statebox.h \
        cornergrabber.h
    
    FORMS    += mainwindow.ui
    

Log in to reply