Qt: resize a QGraphicsItem (boundingRect()) into a QGraphicsScene with the mouse

10,967

Solution 1

I solved my problem. Here is what I have done so far for the mousePressEvent (defining the original boundingRect function like QRectF(-w/2, -h/2, w, h) ):

void Myclass::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    if(isSelected())
    {

    qDebug()<<"isseldeted";
    qreal adjust = 8;
    if((event->pos().x() > boundingRect().left() + adjust) && (event->pos().x() < boundingRect().right() - adjust) && (event->pos().y() < boundingRect().bottom() + adjust) && (event->pos().y() > boundingRect().bottom() - adjust) )
    {
        _adj = event->pos().y();
        _resizemode = true;
        qDebug()<<"bottom";
    }
    if((event->pos().x() > boundingRect().right() - adjust) && (event->pos().x() < boundingRect().right() + adjust) && (event->pos().y() < boundingRect().bottom() + adjust) && (event->pos().y() > boundingRect().bottom() - adjust))
    {
        _adj = event->pos().y();
        _adj2 = event->pos().x();
        _resizemode2 = true;
        qDebug()<<"bottom right";

    }

    if((event->pos().x() > boundingRect().right() - adjust) && (event->pos().x() < boundingRect().right() + adjust) && (event->pos().y() < boundingRect().bottom() - adjust) && (event->pos().y() > boundingRect().top() + adjust))
    {
        _adj2 = event->pos().x();
        _resizemode3 = true;
        qDebug()<<"right";

    }

    if((event->pos().x() > boundingRect().left() - adjust) && (event->pos().x() < boundingRect().left() + adjust) && (event->pos().y() > boundingRect().top() - adjust) && (event->pos().y() < boundingRect().top() + adjust))
    {
        _adj = event->pos().y();
        _adj2 = event->pos().x();
        _resizemode4 = true;
        qDebug()<<"top left";

    }

    if((event->pos().x() > boundingRect().left() - adjust) && (event->pos().x() < boundingRect().left() + adjust) && (event->pos().y() < boundingRect().bottom() - adjust) && (event->pos().y() > boundingRect().top() + adjust))
    {
        _adj2 = event->pos().x();
        _resizemode5 = true;
        qDebug()<<"left";

    }

    if((event->pos().x() > boundingRect().left() - adjust) && (event->pos().x() < boundingRect().left() + adjust) && (event->pos().y() < boundingRect().bottom() + adjust) && (event->pos().y() > boundingRect().bottom() - adjust))
    {
        _adj = event->pos().y();
        _adj2 = event->pos().x();
        _resizemode6 = true;
        qDebug()<<"bottom left";

    }

    if((event->pos().x() > boundingRect().left() + adjust) && (event->pos().x() < boundingRect().right() - adjust) && (event->pos().y() < boundingRect().top() + adjust) && (event->pos().y() > boundingRect().top() - adjust))
    {
        _adj = event->pos().y();
        _resizemode7 = true;
        qDebug()<<"top";

    }

    if((event->pos().x() < boundingRect().right() + adjust) && (event->pos().x() > boundingRect().right() - adjust) && (event->pos().y() < boundingRect().top() + adjust) && (event->pos().y() > boundingRect().top() - adjust))
    {
        _adj = event->pos().y();
        _adj2 = event->pos().x();
        _resizemode8 = true;
        qDebug()<<"top right";

    }
    }
update();
QGraphicsItem::mousePressEvent(event);
}

and for the mouseReleaseEvent:

void Myclass::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if(_resizemode)
{
    prepareGeometryChange();
    _h += event->pos().y() - _adj; //good
    setPos(pos().x(), pos().y() + (event->pos().y() - _adj)/2 );//good

    _resizemode = false;
}

if(_resizemode2)
{
    _h += event->pos().y() - _adj; //good
    _w += event->pos().x() - _adj2;
    setPos(pos().x() + (event->pos().x() - _adj2)/2, pos().y() + (event->pos().y() - _adj)/2 );//good

    _resizemode2 = false;
}

if(_resizemode3)
{
    _w += event->pos().x() - _adj2;
    setPos(pos().x() + (event->pos().x() - _adj2)/2, pos().y());//good

    _resizemode3 = false;
}

if(_resizemode4)
{
    _h -= event->pos().y() - _adj; //good
    _w -= event->pos().x() - _adj2;
    setPos(pos().x() + (event->pos().x() - _adj2)/2, pos().y() + (event->pos().y() - _adj)/2 );//good

    _resizemode4 = false;
}

if(_resizemode5)
{
    _w -= event->pos().x() - _adj2;
    setPos(pos().x() + (event->pos().x() - _adj2)/2, pos().y());//good

    _resizemode5 = false;
}

if(_resizemode6)
{
    _h += event->pos().y() - _adj;
    _w -= event->pos().x() - _adj2;
    setPos(pos().x() + (event->pos().x() - _adj2)/2, pos().y() + (event->pos().y() - _adj)/2);//good

    _resizemode6= false;
}

if(_resizemode7)
{
    _h -= event->pos().y() - _adj;
    setPos(pos().x(), pos().y() + (event->pos().y() - _adj)/2);//good

    _resizemode7= false;
}

if(_resizemode8)
{
    _h -= event->pos().y() - _adj;
    _w += event->pos().x() - _adj2;
    setPos(pos().x() + (event->pos().x() - _adj2)/2, pos().y() + (event->pos().y() - _adj)/2);//good

    _resizemode8= false;
}

update();
QGraphicsItem::mouseReleaseEvent(event);
}

The mouseMoveEvent also need to be implemented:

void Aabb::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{   if(!_resizemode&&!_resizemode2&&!_resizemode3&&!_resizemode4&&!_resizemode5&&!_resizemode6&&!_resizemode7&&!_resizemode8)
    {
    update();
    QGraphicsItem::mouseMoveEvent(event);
    }
}

The problem is that we don't see the resizing in movement: we see the resized item when we release the mouse.

Sometimes the item is not perfectly repositioned I don't know why.

So this is working but I believed it can be improved.

Solution 2

the position of my item is defined with the top left of the boundingRect()

In my opinion, the easiest way is to change this so that the position is defined by the centre of the item. In order to do this, define the original bounding rect as top left (-w/2, -h/2) and bottom right (w/2,h/2) or if you're returning in the boundingRect function QRectF(-w/2, -h/2, w, h) for (x,y,w,h).

Then, create child 'tool' items at the corners, which define the area which you can click and drag the corners of the original item. You may want these just to appear if the item is selected.

In the moveEvent of the child item, update the bounding rect of the main item so that it moves with the child. When the mouse is released, re-calculate the boundingRect of the main item, so that its centre is still at (0,0).

This can be done quite easily if you map the top left and bottom right of the boundingRect and convert them to scene-coordinates, then using the width and height, re-set the item's local coordinates back so that it maintains (-w/2, -h/2, w, h);

Share:
10,967
Jeanstackamort
Author by

Jeanstackamort

Updated on July 26, 2022

Comments

  • Jeanstackamort
    Jeanstackamort almost 2 years

    I would like to resize the boundingRect() of my QGraphicsItem using the mouse.

    To build this I found this topic. So I managed to make it work for the right, the bottomright and the bottom of my boundingRect() following the idea of this the topic.

    But since the position of my item is defined with the top left of the boundingRect() it is more complicated to modify the size of my item moving the edges linked to this position.

    I tried with the top left but the bottom right is also moving. I would like to have the bottom right fixed to only change the size and not the whole position.

    Here is a part of my code:

    void Myclass::mouseMoveEvent(QGraphicsSceneMouseEvent *event) 
    {
        if(_resizemode) //if bottom selected
        {
            prepareGeometryChange();
            _h = event->pos().y();
        }
    
        if(_resizemode2) //if bottom right selected
        {
            prepareGeometryChange();
            _h = event->pos().y();
            _w = event->pos().x();
    
        }
    
        if(_resizemode3) //if right selected
        {
            prepareGeometryChange();
            _w = event->pos().x();
        }
    
        if(_resizemode4) //if top left selected HERE IS MY ISSUE
        {
            prepareGeometryChange();
            setPos(pos().x()+ event->pos().x(), pos().y() + event->pos().y());
            _h = _h - event->pos().y();
            _w = _w - event->pos().x();
    
        }
    
        if(!_resizemode&&!_resizemode2&&!_resizemode3&&!_resizemode4)
        {
        update();
        QGraphicsItem::mouseMoveEvent(event);
        }
    }
    

    _h and _w or the height and the width implemented here:

    QRectF Aabb::boundingRect() const
    {
        return QRectF( 0, 0, _w, _h);
    }
    

    Does someone know how to resize a QGraphicsItem selecting with the mouse each corners of the boundingRect() please?

  • Jeanstackamort
    Jeanstackamort about 10 years
    I see I was also thinking about that but I wanted to avoid all these changes. I will try this thank you. But I would be pleased if someone has a solution without redefining the position of my item.
  • TheDarkKnight
    TheDarkKnight about 10 years
    When I came up with this method, I also looked for an easier solution, but didn't find one. The only way to maintain the origin as you move a corner of the item, is to move the opposite corner at the same time, but this is not what you're wanting. If you can find an easier solution, I'd be interested in knowing how. Good luck ;O)