Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QGraphicsItem resize
Forum Updated to NodeBB v4.3 + New Features

QGraphicsItem resize

Scheduled Pinned Locked Moved Unsolved General and Desktop
17 Posts 6 Posters 12.5k Views 3 Watching
  • 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.
  • W Offline
    W Offline
    Wuzi
    wrote on last edited by
    #1

    Hello,

    I'm trying to make a QGraphicsItem where I can change the size of the object, but I have some problems I cannot solve my self. I found an implementation, but there the resize rectangle will not hide when the parent is not selected.
    Is there better to make 4 Resizerectangle Items for every corner or better to make on GraphicsItem where I paint the selection frame and the resizehandles?
    Whats the different between moving the item or moving the bounding rect of the item?

    Whats the different, when I handle the object in the mouse move event or in the item change event?

    Best regards,

    Martin

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      This stackoverflow thread might be what you are looking for.

      Hope it helps

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      joeQJ 1 Reply Last reply
      1
      • SGaistS SGaist

        Hi,

        This stackoverflow thread might be what you are looking for.

        Hope it helps

        joeQJ Offline
        joeQJ Offline
        joeQ
        wrote on last edited by
        #3

        @SGaist
        Thank u, it helps me now.

        Just do it!

        1 Reply Last reply
        0
        • W Offline
          W Offline
          Wuzi
          wrote on last edited by Wuzi
          #4

          They wrote there that they use mouse move events not the change item event, but for me seems that these events are equal?

          I already found this thread, but there the sizegrips are always visible. For that I read that when I hide the parent then the child will hidden too. I will try this later.

          1 Reply Last reply
          0
          • mrjjM Offline
            mrjjM Offline
            mrjj
            Lifetime Qt Champion
            wrote on last edited by
            #5

            Just as a note:
            There is also
            http://www.davidwdrell.net/wordpress/?page_id=46
            But i think the version @SGaist links to is better made. :)

            1 Reply Last reply
            0
            • W Offline
              W Offline
              Wuzi
              wrote on last edited by
              #6

              At the moment I use itemChange to move the parent. It works fine when the item is on scene coords (0,0). But when I move and release and try to move a second time. the item and his parent jumps back to (0,0). And begins than to move. How I can solve this to move item and his parent?

              QVariant ResizeItem::itemChange(GraphicsItemChange change,const QVariant &value){
              
              
                  if (change == ItemPositionChange) {
              
                      QPointF newPos = value.toPointF();
              
                      qreal xV = round(newPos.x()/gridsize)*gridsize;
                      qreal yV = round(newPos.y()/gridsize)*gridsize;
              
                      parentItem()->setPos(mapToParent(QPointF(xV,yV)));
                      return QGraphicsItem::itemChange(change, pos()); // don't change position of item just position of parent
              
                  }else if(change == ItemSelectedChange ){ // !isSelected() because seletion is after this event
              
                      return QGraphicsItem::itemChange(change, value);
              
                  }else{
              
                      return QGraphicsItem::itemChange(change, value);
                  }
              
              }
              
              S 1 Reply Last reply
              0
              • W Wuzi

                At the moment I use itemChange to move the parent. It works fine when the item is on scene coords (0,0). But when I move and release and try to move a second time. the item and his parent jumps back to (0,0). And begins than to move. How I can solve this to move item and his parent?

                QVariant ResizeItem::itemChange(GraphicsItemChange change,const QVariant &value){
                
                
                    if (change == ItemPositionChange) {
                
                        QPointF newPos = value.toPointF();
                
                        qreal xV = round(newPos.x()/gridsize)*gridsize;
                        qreal yV = round(newPos.y()/gridsize)*gridsize;
                
                        parentItem()->setPos(mapToParent(QPointF(xV,yV)));
                        return QGraphicsItem::itemChange(change, pos()); // don't change position of item just position of parent
                
                    }else if(change == ItemSelectedChange ){ // !isSelected() because seletion is after this event
                
                        return QGraphicsItem::itemChange(change, value);
                
                    }else{
                
                        return QGraphicsItem::itemChange(change, value);
                    }
                
                }
                
                S Offline
                S Offline
                samdol
                wrote on last edited by samdol
                #7

                @Wuzi
                As far as I remember the link mrjj provided also shows the similar side effect. And here is how solved it:
                When you reimplement mouseReleaseEvent on your ResizeItem class you may forgot to include QGraphicsItem::mouseReleaseEvent(event);
                So it must be look like this

                void ResizeItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
                {
                    if(...){
                        ...
                    }
                    QGraphicsItem::mouseReleaseEvent(event);
                }
                
                
                W 1 Reply Last reply
                0
                • S samdol

                  @Wuzi
                  As far as I remember the link mrjj provided also shows the similar side effect. And here is how solved it:
                  When you reimplement mouseReleaseEvent on your ResizeItem class you may forgot to include QGraphicsItem::mouseReleaseEvent(event);
                  So it must be look like this

                  void ResizeItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
                  {
                      if(...){
                          ...
                      }
                      QGraphicsItem::mouseReleaseEvent(event);
                  }
                  
                  
                  W Offline
                  W Offline
                  Wuzi
                  wrote on last edited by
                  #8

                  @samdol said in QGraphicsItem resize:

                  When you reimplement mouseReleaseEvent on your ResizeItem class you may forgot to include QGraphicsItem::mouseReleaseEvent(event);

                  But I didn't implement a mouseReleaseEvent, I just use itemChange event, because there I get the old and new position.
                  I debugged my project and found out, that the ItemPosition Change will challed two times, the first time sets every coords to zero, and the second time it moves the item. I thought, that when I use parentItem()->setPos there shouldn't be an item change on the child? Could this be the problem?

                  1 Reply Last reply
                  0
                  • W Offline
                    W Offline
                    Wuzi
                    wrote on last edited by
                    #9

                    I checked out the coords of the items:

                    QVariant ResizeItem::itemChange(GraphicsItemChange change,const QVariant &value){
                    
                        if (change == ItemPositionHasChanged) {
                    
                            QPointF newPos = value.toPointF(); // (0,-100)
                    
                            QPointF point = scenePos(); // (0,-100)
                            QPointF temp5 = parentItem()->scenePos(); // (0,0)
                            QPointF temp3 = mapToParent(newPos); //(0,-200)
                            QPointF point4 = mapToScene(pos()); // (0,-200)
                            QPointF temp = pos(); // (0,-100)
                            QPointF temp2 = parentItem()->pos(); // (0,0)
                            QRectF temp213 = parentItem()->boundingRect(); // (0,0,300,300)
                            QRectF temp532 = boundingRect(); // (0,0,301,301)
                            parentItem()->setPos(mapToParent(newPos));
                            QPointF tem6 = parentItem()->pos(); // (0,-200)
                            return pos(); //QPointF(xV,yV);//QGraphicsItem::itemChange(change, pos()); // don't change position of item just position of parent
                    
                        }else if(change == ItemPositionChange){
                    
                            QPointF newPos = value.toPointF();
                            qreal xV = round(newPos.x()/gridsize)*gridsize;
                            qreal yV = round(newPos.y()/gridsize)*gridsize;
                    
                            return QPointF(xV,yV);
                    

                    Why temp3 is not the same than newPos?

                    A 1 Reply Last reply
                    0
                    • W Offline
                      W Offline
                      Wuzi
                      wrote on last edited by Wuzi
                      #10

                      When I debug the program it works fine, but when I start it normaly it moves faster than the mouse. Is it restricted to move the parentItem without moving the item itself while itemChange will called (is there a recursiv call that moves the parent item to fast)?

                      1 Reply Last reply
                      0
                      • W Wuzi

                        I checked out the coords of the items:

                        QVariant ResizeItem::itemChange(GraphicsItemChange change,const QVariant &value){
                        
                            if (change == ItemPositionHasChanged) {
                        
                                QPointF newPos = value.toPointF(); // (0,-100)
                        
                                QPointF point = scenePos(); // (0,-100)
                                QPointF temp5 = parentItem()->scenePos(); // (0,0)
                                QPointF temp3 = mapToParent(newPos); //(0,-200)
                                QPointF point4 = mapToScene(pos()); // (0,-200)
                                QPointF temp = pos(); // (0,-100)
                                QPointF temp2 = parentItem()->pos(); // (0,0)
                                QRectF temp213 = parentItem()->boundingRect(); // (0,0,300,300)
                                QRectF temp532 = boundingRect(); // (0,0,301,301)
                                parentItem()->setPos(mapToParent(newPos));
                                QPointF tem6 = parentItem()->pos(); // (0,-200)
                                return pos(); //QPointF(xV,yV);//QGraphicsItem::itemChange(change, pos()); // don't change position of item just position of parent
                        
                            }else if(change == ItemPositionChange){
                        
                                QPointF newPos = value.toPointF();
                                qreal xV = round(newPos.x()/gridsize)*gridsize;
                                qreal yV = round(newPos.y()/gridsize)*gridsize;
                        
                                return QPointF(xV,yV);
                        

                        Why temp3 is not the same than newPos?

                        A Offline
                        A Offline
                        Asperamanca
                        wrote on last edited by
                        #11

                        @Wuzi said in QGraphicsItem resize:

                        Why temp3 is not the same than newPos?

                        mapToParent converts coordinates from "this" item's coordinate system to the parent item's coordinate system. Compared to it's parent, "this" item has an offset of (0,-100). Therefore, any position you enter into mapToParent at this point will get that offset.

                        Your mistake here is that you take a position (newPos) which is already in the parent's coordinate system (because the position of an item is always given relative to it's parent), and map it - again - into the parent's coordinate system.

                        What you need to get point4 is parentItem()->mapToScene(newPos) - provided that parentItem() is not NULL.

                        1 Reply Last reply
                        0
                        • W Offline
                          W Offline
                          Wuzi
                          wrote on last edited by
                          #12

                          parentItem()->setPos(parentItem()->mapToScene(xV,yV));
                          parentItem()->moveBy(xV,yV);

                          I tried your hint, but this does not change something. I tried also moveBy (because xV,yV is everytime a delta value). But has the same effect.

                          I uploaded the project to dropbox:
                          https://www.dropbox.com/s/1skrl8p0b5yq5ua/Grafik.zip?dl=0

                          A 1 Reply Last reply
                          0
                          • W Wuzi

                            parentItem()->setPos(parentItem()->mapToScene(xV,yV));
                            parentItem()->moveBy(xV,yV);

                            I tried your hint, but this does not change something. I tried also moveBy (because xV,yV is everytime a delta value). But has the same effect.

                            I uploaded the project to dropbox:
                            https://www.dropbox.com/s/1skrl8p0b5yq5ua/Grafik.zip?dl=0

                            A Offline
                            A Offline
                            Asperamanca
                            wrote on last edited by
                            #13

                            @Wuzi said in QGraphicsItem resize:

                            parentItem()->setPos(parentItem()->mapToScene(xV,yV));
                            parentItem()->moveBy(xV,yV);

                            I tried your hint, but this does not change something. I tried also moveBy (because xV,yV is everytime a delta value). But has the same effect.

                            I uploaded the project to dropbox:
                            https://www.dropbox.com/s/1skrl8p0b5yq5ua/Grafik.zip?dl=0

                            Well, I only explained why temp3 is not the same as newPos. I didn't know (from the code) what your intention was.
                            If we are talking about the code for a size handle (and the size handle should resize it's parent item), let's take it step by step:

                            • Let's just consider the bottom right size handle. The one that only changes the parent item's size, but not it's position
                            • That size handle should be moveable (though itemFlag)
                            • You can restrict movement to a grid, much like you do in the "ItemPositionChange" section of code. But for a start, I would leave that part out until the resizing works properly
                            • Your parentItem needs some way to change it's size from the outside.
                            • We know that our size handle should be at the bottom-right of the parent item's boundingRect. Therefore, if the handle is moved, we can calculate how the parent's boundingRect must change to reflect the change in size

                            That should work with something like this (just off the top of my head)

                            // In the size handle
                            if (change == ItemPositionHasChanged)
                            {
                               QRectF parentBoundingRect = parentItem().boundingRect();
                               // Correct boundingRect so the bottomRight matches the new handle position
                               // Both the parent's boundingRect and pos() are in the parentItem's coordinate system, so no need to map anything
                               parentBoundingRect.setBottomRight(pos());
                               //MISSING: Here you need some way to apply the new boundingRect to your parent
                               // Note: As long as neither the topLeft of the boundingRect, nor the position of the parent changes, we should not need to adjust the handle position in any way
                            }
                            

                            And regarding your question "what's the difference between your item's position and the topLeft of your boundingRect?"
                            In theory, you can always choose whether to move the item around using setPos, or whether to translate the boundingRect and leave the position always on 0/0. To add confusion, you can also use transformations to move an item around.

                            In practice, I find it useful to design the boundingRect in such a way that its 0/0 position is some kind of anchor or "special point" of the object. For example, if I draw a circle, it might make sense to have the origin of the boundingRect in the center. In the circle's item coordinate, the boundingRect would have a negative topLeft, e.g. (-5, -5) and a matching size (10/10). That way, when you apply a scaling transformation to the circle, it will grow or shrink without moving around, because the origin of the boundingRect is (by default) the transformation origin.
                            In summary, having a "sensible" origin for items, and then moving them around using setPos is usually much easier.

                            1 Reply Last reply
                            2
                            • W Offline
                              W Offline
                              Wuzi
                              wrote on last edited by
                              #14

                              Thank you Asperamanca for your explanation, I will need it later, but at the moment I would like just to move the parent item. My plan is: when I move the resizeItem, I catch the new position, change the position of the parent ( so resizeitem changes position absolute to, but not relative to parent and no new itemChange event will called), but the position of the item should not change relative to the parent (so I return pos(), the value before I moved the item). It works fine, that the resizeitem stays in the parent item, but if I move the resizeitem to fast, the parent with the resizeitem moves faster than the mouse. If I debug every position change it works fine, but I don't understand why it moves faster than the mouse?

                              1 Reply Last reply
                              0
                              • A Offline
                                A Offline
                                Asperamanca
                                wrote on last edited by
                                #15

                                The "jumping ahead" effect usually occurs because the child item you move around is affected by the repositioning of the parentItem after all, or because coordinate systems are mixed up in some place.

                                However, in your case I suspect an incorrect assumption: While in "ItemPositionHasChanged", pos() is already the new value. The return value of itemChange is ignored in this case. From the docs:
                                "The value argument is the new position (the same as pos()), and QGraphicsItem ignores the return value for this notification (i.e., a read-only notification)."

                                You might get something like this to work in the "ItemPositionChange", however I do not know whether it's good to change an item's parent's position while in the "ItemPositionChange" itself.

                                There is a totally different approach, though it is somewhat more work (especially if you want to get it watertight):

                                • Overload mousePress, mouseMove and mouseRelease events (you can do the same with sceneEvent, by the way)
                                • Recognize when a drag start and ends. The simplest form: press with left button, release with left button
                                • When a drag starts, grab the mouse and store the drag (mouse) start position in scene coordinates
                                • When a mouseMove event arrives while a drag is running, compare the current mouse position with the drag start position
                                • Use that delta to reposition your parent. Since we are working in scene coordinates, moving the parent around won't affect our coordinate system. When we move the parent towards the drag position, the next drag delta will be that much smaller. This works very well with snap-to-grid, too.
                                • Ungab the mouse when the drag ends
                                1 Reply Last reply
                                1
                                • W Offline
                                  W Offline
                                  Wuzi
                                  wrote on last edited by
                                  #16

                                  Thank you Asperamanca, I will try it and report the result here. Thank you!

                                  1 Reply Last reply
                                  0
                                  • W Offline
                                    W Offline
                                    Wuzi
                                    wrote on last edited by
                                    #17

                                    Thank you Asperamanca, your hint with using mouse move instead of ItemChange works fine:

                                    void ResizeItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event){
                                    
                                        if( event->buttons() & Qt::LeftButton){ // If Leftbutton pressed
                                    
                                            QPointF delta = parentItem()->mapToParent(event->pos())-parentItem()->pos()-mouse_pos_parent_coords;
                                            parentItem()->moveBy(delta.x(), delta.y());
                                            return;
                                    
                                        }
                                    
                                        QGraphicsItem::mouseMoveEvent(event);
                                    }
                                    
                                    
                                    void ResizeItem::mousePressEvent(QGraphicsSceneMouseEvent *event){
                                    
                                        mouse_pos_parent_coords = event->pos();
                                        QGraphicsItem::mousePressEvent(event);
                                    }
                                    

                                    If somebody know, why it does not work to use ItemChange I will happy to know it :)

                                    1 Reply Last reply
                                    0

                                    • Login

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