PDA

View Full Version : bad sceneRect with scaled text



koosh
8th July 2008, 03:11
In a subclassed QGraphicsTextItem, I'm drawing some text and scaling it down in size to fit into a small area in the Scene. (I found that I have to scale, because the needed size is smaller than what I can get by using a small point size with setFont().) I adjust the scale as follows, depending on the maxHeight that I want to see in the scene.


setFont(QFont("Times", 40));
setDefaultTextColor(QColor(Qt::white));
QFontMetricsF fm(font());
qreal s = maxHeight / fm.height();
scale(s, -s);
translate(-(fm.width(net)/2), -(fm.height()/2));
setPlainText(net);

The text is displayed properly. However, when I try zooming to fit, using the code below, the sceneRect is much, much larger than what I expect. So, the zoom doesn't work right. Without the text everything works fine. When I add the text the zoomed view shows everything crammed into a tiny area in a corner with empty space covering the rest of the view. It's almost as if the sceneRect() is being computed using unscaled, rather than scaled text.


pcbDoc->getScene()->setSceneRect(QRectF());
view->fitInView(pcbDoc->getScene()->sceneRect(), Qt::KeepAspectRatio);

Obviously I'm doing something wrong, but I need a hint.
Thanks!

wysota
8th July 2008, 07:29
Where did you put the first snippet of code you presented?

koosh
8th July 2008, 23:26
I placed it in the constructor of my subclassed QGraphicsTextItem class.

wysota
8th July 2008, 23:29
Could you prepare a minimal compilable application reproducing the problem?

koosh
9th July 2008, 00:35
I just hacked something into the Qt Elastic Nodes example, and it seems to work as expected - the problem doesn't occur there....

hmm... I must have some stupid mistake in my code. I'll check again.

koosh
9th July 2008, 01:14
I think the problem is related to the fact that sceneRect() always grows in size but never shrinks, even if you set a null sceneRect(), it will return a size that is the largest the scene extents have ever been.

For zooming to fit, I want to know the bounding rect of the current scene, not what it might have been in the past. I changed my zoom function to use itemsBoundingRect() instead and it works. This isn't my preferred solution, as it takes too long to compute. I think I will change my code to maintain my own overall bounding rect, and then use that in the zoom-to-fit function.

I'm still not sure why the text resulted in such a large sceneRect... The sceneRect is computed using the using the transformed / scaled items, right?

wysota
9th July 2008, 04:50
I think the problem is related to the fact that sceneRect() always grows in size but never shrinks, even if you set a null sceneRect(), it will return a size that is the largest the scene extents have ever been.
Not really. It will return the minimum size to contain all the items. If you move items closer to each other and reset the scene size, it will decrease its size.


I'm still not sure why the text resulted in such a large sceneRect... The sceneRect is computed using the using the transformed / scaled items, right?

No, sceneRect is sceneRect. It doesn't change regardless of the zoom. You zoom the view, not the scene. The Earth doesn't become bigger if you move closer to it - it is just your impression because you SEE it bigger.

koosh
9th July 2008, 21:09
Wysota, thanks for helping me to understand. Perhaps I'm misinterpreting the Qt documentation regarding scenerect:



If unset, or if set to a null QRectF, sceneRect() will return the largest bounding rect of all items on the scene since the scene was created (i.e., a rectangle that grows when items are added to or moved in the scene, but never shrinks).

So does it ever shrink or not?

I'm scaling the GraphicsTextItem. So, that means the Text is stored in the scene as scaled text, not unscaled, right? I understand that zooming the view doesn't change the scene, but this is different, right? I'm talking about scaling the item in the scene, not the view. The scene Rect that is computed should be for text as it is actually stored in the scene (scaled down), regardless of the view.

Thanks.

wysota
9th July 2008, 21:19
So does it ever shrink or not?
Not by itself, but if you reset the size (for instance by setting it to some real value and then to an invalid one again), it will shrink.


I'm scaling the GraphicsTextItem. So, that means the Text is stored in the scene as scaled text, not unscaled, right?
Yes, but the sceneRect doesn't change. Only the space covered by the item on the scene changes.


The scene Rect that is computed should be for text as it is actually stored in the scene (scaled down), regardless of the view.
I don't really understand what you mean, but you are probably right :)

koosh
9th July 2008, 22:06
Not by itself, but if you reset the size (for instance by setting it to some real value and then to an invalid one again), it will shrink.



Ok, I think I see.... I was expecting the sceneRect() be be managed entirely by the QGraphicsScene, but I realize that I really should be mantaining the sceneRect and calling setSceneRect( ) as I change the scene. I looked at the QT code, and there it recommends that we should always call setSceneRect() when operating on large scenes, because otherwise if we ask QGraphicsScene to compute it , it just iterates over all items on the scene calling itemsBoundingRect(). (this is time consuming and what I wanted to avoid).



Yes, but the sceneRect doesn't change. Only the space covered by the item on the scene changes.


This seems counter-intuitive. For example, if I create a rect of size (10,10), and then scale it by (0.1, 0.1) and add it to a scene, the sceneRect returns (10,10), even though the rect is only covering an area of (1,1). My expectation was that the sceneRect would return (1,1) because it would have applied the item's transformation.



I don't really understand what you mean, but you are probably right :)

Put another way: the item transformation (scaling) is only used when rendering the item to a graphics view. The sceneRect computation doesn't consider item transformation.

wysota
9th July 2008, 23:03
This seems counter-intuitive.
It might be a bug.


My expectation was that the sceneRect would return (1,1) because it would have applied the item's transformation.
Maybe you should try switching the order of operations, maybe that helps.

koosh
9th July 2008, 23:09
It might be a bug.


Maybe you should try switching the order of operations, maybe that helps.

I tried that a few days back, and IIRC, it caused a change, but not an improvement.

koosh
10th July 2008, 06:43
So is it true that in general for large scenes, I should be managing the sceneRect() myself, and calling setSceneRect() for what I want the overall scene to be? Or is this really only necessary if I scale or otherwise transform any graphicsitems, and if not, let qgraphicsscene do it for me?

What is the best practice regarding this?

thx!

wysota
10th July 2008, 12:24
The best practice is to manage the scene size yourself.

koosh
10th July 2008, 19:29
Ok, thank you.