I am trying to create a QGraphicsView
that will allow someone to scale the current QGraphicsItem
to fit the size of the QGraphicsView
window.
I have overridden QGraphicsItem
to create a custom version, and I implemented some methods so it knows how much it has been scaled (which is always proportional to the original, so there is only one scale factor - the same for width and height).
So in the scaleFactor
setter I have the following:
void ImagePixmapItem::setScaleFactor(float sf){
scaleFactor = sf;
this->boundingRect().setWidth(this->boundingRect().width()*scaleFactor);
this->boundingRect().setHeight(this->boundingRect().height()*scaleFactor);
}
And in my main form, I have the following in a button:
QRect portRect = ui->graphicsView->viewport()->rect();
double scaleFactorX;
if(portRect.width() <= (item->boundingRect().size().width()))
scaleFactorX =portRect.width() /(item->boundingRect().size().width());
else
scaleFactorX = (item->boundingRect().size().width())/portRect.width();
qDebug("Scalefactor: %4.3f \n", scaleFactorX);
qDebug("item width: %4.3f \n", item->boundingRect().size().width());
qDebug("item height: %4.3f \n", item->boundingRect().size().height());
item->setScaleFactor(scaleFactorX);
item->scale(scaleFactorX,scaleFactorX);
Where item
is one of those ImagePixmapItem
s.
This works good the first time time - my image is larger than the viewport, and it scales down nicely to fit the window (at least width wise). However, if I hit the button again, the same value for scaleFactorX
and item
width and height come back.
Can you change the boundingRect
of an image after it has been transformed? If not, what should I do?
First of all, QGraphicsItem::boundingRect()
returns a copy of the rect. Changing it has no effect on the actual item. To change an item's geometry, you need to override that function and return a different rect. And call prepareGeometryChange()
when you actually change it.
Now, if all you want is to fit the item in QGraphicsView's viewport, use QGraphicsView::fitInView()
.
Changing the transformation of an item is very different from changing the transformation from the scene to the view. The former changes how the item is placed in the scene in relation to other items. The later keeps the relation and only affect how the scene is "reflected" onto the view.
It doesn't make much difference if you have a single item in the scene. Just keep in mind when you are dealing more complex scene that item transformation deals with the mathematical model of your world, not how to view it.
Edit:
I just reread your code. It turns out you are calculating the scale factor wrong. Here's a basic, non-tested code:
QRect itemSize = graphicsView->mapFromScene(item->sceneBoundingRect()).boundingRect().size();
QRect scaledSize =itemSize.scale(graphicsView->viewport().size(), Qt::KeepAspectRatio);
double ratio = qMin((double)scaledSize.width()/itemSize().width(), (double)scaledSize.height()/itemSize().height());
item->setTransform(QTransform::fromScale(ratio,ratio), true);
The point is to use sceneBoundingRect
instead of boundingRect
since boundingRect
is the item local bounds which is always the same regardless of item transform. And sceneBoundingRect is the bounds after all transformations
are applied.