2

I've made a QGraphicsScene with a mouseClickEvent that lets the user create blue squares inside of it. But I want to make the scene grow when an item is placed against its border so that the user never runs out of space on the graphics scene.

What's the best way to make a graphics scene bigger in this case?

Pieter
  • 31,619
  • 76
  • 167
  • 242

3 Answers3

4

I suggest doing something like the following:

  1. Get the bounding rect of all items in the scene using QGraphicsScene::itemsBoundingRect().
  2. Add some padding around that rect to make sure the bounds of the items won't hit the edge of the view. Something like myRect.adjust(-20, -20, 20, 20) should be sufficient.
  3. Use QGraphicsView::fitInView(myRect, Qt::KeepAspectRatio) to ensure the taken area is within the visible bounds of the view.

That should do it. This code should be called whenever something has changed in the scene. You can use QRectF::intersects() function to find out if the new rect has been placed on the edge of the view.

What's the best way to make a graphics scene bigger in this case?

The GraphicsScene is an infinite coordinate system. Most clients will use itemsBoundingRect() to get an idea how much space is actually used by items in the scene. If you have cleared the scene, you might want to call QGraphicsScene::setSceneRect(QRectF()) to "make it smaller" again.

Hope that helps.

BastiBen
  • 19,679
  • 11
  • 56
  • 86
  • +1 for a clear answer. But what if I don't want the content to be resized to fit the screen and go with a scrollbar solution instead? – Pieter Nov 22 '10 at 12:40
  • Wait, found it... I have to use `setSceneRect` on the graphics view. – Pieter Nov 22 '10 at 12:45
1

sorry if this is a little bit late(6 years) but I will provide an answer if someone still struggling with this or want another approach.I implement this in mouseReleaseEvent in the custom class derive from QGraphicsObject. Note that I initialize the size of my QGraphicsScene (1000,1000) with the following code.scene->setSceneRect(0,0,1000,1000). So here what my code will do. If the Item(the item is draggable) placed against the border, that border will increase. So here is my code:

void MyItem::mouseReleaseEvent(QgraphicsceneMouseEvent* event){
  QRectF tempRect = this->scene()->sceneRect();
  if(this->scenePos().y() < this->scene()->sceneRect().top()){
      tempRect.adjust(0,-200,0,0);
      if(this->scenePos().x() < this->scene()->sceneRect().left()){
          tempRect.adjust(-200,0,0,0);
      }
      else if(this->scenePos().x() + 200> this->scene()->sceneRect().right()){
        tempRect.adjust(0,0,200,0);
      }
  }
  else if(this->scenePos().y() + 200 > this->scene()->sceneRect().bottom()){
      tempRect.adjust(0,0,0,200);
      if(this->scenePos().x() < this->scene()->sceneRect().left()){
          tempRect.adjust(-200,0,0,0);
     }
     else if(this->scenePos().x() + 200> this->scene()->sceneRect().right()){
        tempRect.adjust(0,0,200,0);
     }
 }
 else if(this->scenePos().x() < this->scene()->sceneRect().left()){
      tempRect.adjust(-200,0,0,0);
      if(this->scenePos().y() < this->scene()->sceneRect().top()){
          tempRect.adjust(0,-200,0,0);
      }
      else if(this->scenePos().y() + 200 > this->scene()->sceneRect().bottom()){
          tempRect.adjust(0,0,0,200);
      }
  }
  else if(this->scenePos().x() + 200> this->scene()->sceneRect().right()){
      tempRect.adjust(0,0,200,0);
      if(this->scenePos().y() < this->scene()->sceneRect().top()){
          tempRect.adjust(0,-200,0,0);
      }
      else if(this->scenePos().y() + 200 > this->scene()->sceneRect().bottom()){
          tempRect.adjust(0,0,0,200);
      }
  }

  this->scene()->setSceneRect(tempRect);
AAEM
  • 1,837
  • 2
  • 18
  • 26
0

I know its late, but for anyone looking for python code here:

class Scene(QtWidgets.QGraphicsScene):
    def __init__(self):
        super(Scene, self).__init__()
        self.setSceneRect(0, 0, 2000, 2000)

        self.sceneRect().adjust(-20, -20, 20, 20)
        self.old_rect = self.itemsBoundingRect()

    def adjust(self):
        w = self.sceneRect().width()
        h = self.sceneRect().height()
        x = self.sceneRect().x()
        y = self.sceneRect().y()
        adjust_factor = 500
        adjust_factor2 = 300

        smaller = self.is_smaller()
        self.old_rect = self.itemsBoundingRect()

        if not self.sceneRect().contains(self.old_rect):
            self.setSceneRect(-adjust_factor + x, -adjust_factor + y, adjust_factor + w, adjust_factor + h)

        if smaller:
            self.setSceneRect(adjust_factor2 + x, adjust_factor2 + y, abs(adjust_factor2 - w), abs(adjust_factor2 - h))

    def is_smaller(self):

        x = self.old_rect.x()
        y = self.old_rect.y()

        h = self.old_rect.height()
        w = self.old_rect.width()

        if ((x <= self.itemsBoundingRect().x()) and (y <= self.itemsBoundingRect().y())
                and (h > self.itemsBoundingRect().height()) and (w > self.itemsBoundingRect().width())):
            return True

        return False

Explanation:

  1. use self.sceneRect().contains(self.itemBoundingRect) check whether the itemBoundingRect is within the sceneRect, if its not in the sceneRect then use self.setSceneRect() to increase the sceneRect size (Note: make sure you add to the previous sceneRect like shown in the above code).

  2. If you also want to decrease the sceneRect. Store the old itemBoundingRect and compare it with the new one, if the new itemSceneRect Rectangle is smaller then decrease the size by some factor (refer to the above code).

Usage:

you may call the adjust method from anywhere you like. But Calling the adjust method from mouseReleaseEvent worked the best for me.

*If you have any suggestions or query you may comment.

JacksonPro
  • 3,135
  • 2
  • 6
  • 29