PDA

View Full Version : QGraphicsView scaling horizontally



pssss
18th March 2011, 14:39
I have a QGraphicsItem subclass that is a rectangle with text on it. I want to be able to zoom in from the view but the rectangles should only be scaled horizontally. I can't do it like this view->scale(2,1) because then the text and the edges of the QGraphicsItems will get warped. In other words, the rectangles should appear to increase in width but the text on these rectangles should stay the same size.

To do that properly I have to modify the scene to change the width of the rectangles every time I zoom in or zoom out. This in itself is not a problem because I only have one view and it works fine but I think it diminishes the point of separating the view from the scene since zooming is something that is only related to how you view the scene. It also adds a lot of ugly code to the qgraphicsitem subclass and the qgraphicsscene subclass.


There are other solutions like painting the text on the rectangles from the view but that is even uglier than changing the width of the rectangles.


Does anyone know of a better solution?

Thanks in advance.

wysota
18th March 2011, 20:01
You can set the ItemIgnoresTransformations on the text items. Then you can scale their parent (the rectangle) normally and optionally adjust the text to the new width of the rectangle. However I think that simply increasing the width of the rect is a much simpler and better idea. It's also an option to overpaint the rectangle directly on the view's viewport instead of making it an item.

pssss
18th March 2011, 22:00
You can set the ItemIgnoresTransformations on the text items. Then you can scale their parent (the rectangle) normally and optionally adjust the text to the new width of the rectangle. However I think that simply increasing the width of the rect is a much simpler and better idea. It's also an option to overpaint the rectangle directly on the view's viewport instead of making it an item.

Thanks, painting on the view's viewport sounds good (would I do this from the view's paintEvent()?). But I don't see any function to get only those items that are currently visible from the view. If I'm not mistaken I would have to loop though all the items checking one by one if they are visible and this would ignore all the efficient algorithms and data structures that QGraphicsView has behind the scenes.

If I'm mistaken and you can do it efficiently then I'll give it a try. Can you?

Thanks again.

wysota
18th March 2011, 22:57
would I do this from the view's paintEvent()?
Yes.

But I don't see any function to get only those items that are currently visible from the view.
What do you need this for?


If I'm not mistaken I would have to loop though all the items checking one by one if they are visible and this would ignore all the efficient algorithms and data structures that QGraphicsView has behind the scenes.
If I understand that you mean you would have to paint all the items yourself then no, you wouldn't. Simply call the base class implementation of the paint event.

pssss
18th March 2011, 23:34
Yes.

What do you need this for?


If I understand that you mean you would have to paint all the items yourself then no, you wouldn't. Simply call the base class implementation of the paint event.

Thanks for the quick reply. I think I need to do that to follow your advice:
"It's also an option to overpaint the rectangle directly on the view's viewport instead of making it an item."

I have very many rectangles not just one, some wouldn't be visible since you can scroll the view. QGraphicsView only paints those which are currently visible. If I have to loop linearly over all the scene's rectangles to paint only the ones that are visible it would take O(n). But I think QGraphicsView uses some tree structure behind the scenes to make it much more efficient to check which items need to be painted, I guess it's O(log n).

I only see the function items() in the QGraphicsView API but this one returns all the scene's items, not just the visible ones.

I could be wrong about all the above, if I am, should I just loop over all the items from items() and paint the visible ones?

wysota
18th March 2011, 23:36
I don't really get what you mean. Why would you have to paint something that is not visible?

pssss
18th March 2011, 23:44
That's what I don't want. I only want to paint the visible ones. But I can only get a list of all the items, regardless of whether they are visible or not. From this list I have to find out which ones are visible, to paint only those. If I have to loop through this list it would take a lot of time, O(n). I was wondering if there is a way to get a list of only those items that are visible within a QGraphicsView, so I don't have to iterate over the whole list of all items.

wysota
18th March 2011, 23:48
That's what I don't want. I only want to paint the visible ones. But I can only get a list of all the items, regardless of whether they are visible or not. From this list I have to find out which ones are visible, to paint only those.
Why and where do you want to paint those items?

pssss
19th March 2011, 00:03
Why and where do you want to paint those items?

Thanks for your patience. I have QGraphicsItems which are rectangles with text on them. The paintEvent of the item itself wouldn't work because of the reasons from the first post, it wouldn't scale properly. Taking your advice I would paint them from the view however I want it, but I would still store those rectangles with text on them as QGraphicsItem, however the paintEvent function of these items wouldn't do anything since they would be painted from the view.

in the subclass of QGraphicsItem I would have: paintEvent(QPaintEvent * event) {}

To paint them I would go to the paintEvent() function from the subclass of QGraphicsView and paint those items from there according to the transformation that the view has.

I could use something else instead of a QGraphicsItem subclass to store those rectangles but it's more convenient for me to store them like that. I could have a list of QRects (or subclass of QRects) stored in the scene but again I prefer to have those rectangles as QGraphicsItems, even if the paintEvent() of the items is empty.

wysota
19th March 2011, 00:10
Thanks for your patience. I have QGraphicsItems which are rectangles with text on them. The paintEvent of the item itself wouldn't work because of the reasons from the first post, it wouldn't scale properly. Taking your advice I would paint them from the view however I want it, but I would still store those rectangles with text on them as QGraphicsItem, however the paintEvent function of these items wouldn't do anything since they would be painted from the view.

in the subclass of QGraphicsItem I would have: paintEvent(QPaintEvent * event) {}
Items don't have a paintEvent. They have a paint() routine.


To paint them I would go to the paintEvent() function from the subclass of QGraphicsView and paint those items from there according to the transformation that the view has.

I could use something else instead of a QGraphicsItem subclass to store those rectangles but it's more convenient for me to store them like that. I could have a list of QRects (or subclass of QRects) stored in the scene but again I prefer to have those rectangles as QGraphicsItems, even if the paintEvent() of the items is empty.
If you want to repeat all that QGraphicsView does (transformations, scrolling, clipping, etc.) only to make the text fit the item that scales in horizontal direction only then it's much better to use Graphics View to its full potential and only tweak the scaling and fitting as told at the beginning. At worst you'll have to implement your own item class.

pssss
19th March 2011, 00:28
Ok, I'll just leave it like I have it which changes the width.

Thanks for your help.