PDA

View Full Version : how to prevent qgraphicsitem repaint while mouse move on it



christina123y
8th April 2009, 14:48
Hi,everyone. I have found a problem which troubled me for a long time:
That when i move mouse, the class which inherit from qgraphicsitem will be repainted? And this have obviously slower my graph(which drawed in the class inherits from qgraphicsItem) .
how can i prevent when the mouse move ,and the item won't be repainted?
help me soonly ! really need your help . thank you.

wysota
8th April 2009, 15:45
That when i move mouse, the class which inherit from qgraphicsitem will be repainted?
Yes, it might be.


And this have obviously slower my graph(which drawed in the class inherits from qgraphicsItem) .
how can i prevent when the mouse move ,and the item won't be repainted?


There are at least three different ways to handle your situation. One possibility is to render contents of your item to a pixmap and only update the pixmap when you're not moving the item and if you are then render the old contents. Second possibility is to enable one of the caching modes for the item which does essentially more or less the same. I forgot the third solution :)

lni
8th April 2009, 16:47
There are at least three different ways to handle your situation. One possibility is to render contents of your item to a pixmap and only update the pixmap when you're not moving the item and if you are then render the old contents. Second possibility is to enable one of the caching modes for the item which does essentially more or less the same. I forgot the third solution :)

I am having the same problem, that the QGraphicsItem will do unnecessary paint when the window lose/gain focus or on a mouse movement, even though there is no actual new exposure event occurring.

I think this is a bug that Qt should fix, rather than asking application developers to find a workaround...

wysota
8th April 2009, 17:51
I am having the same problem, that the QGraphicsItem will do unnecessary paint when the window lose/gain focus or on a mouse movement, even though there is no actual new exposure event occurring.

:)


I think this is a bug that Qt should fix, rather than asking application developers to find a workaround...

This time I won't enter this flamewar. I don't agree with you but you have the right to have a different opinion. I can only say "read the docs".

christina123y
9th April 2009, 04:12
Yes, it might be.



There are at least three different ways to handle your situation. One possibility is to render contents of your item to a pixmap and only update the pixmap when you're not moving the item and if you are then render the old contents. Second possibility is to enable one of the caching modes for the item which does essentially more or less the same. I forgot the third solution :)


Hi, I have solved this problem through your second method.
i am very grategful for your help. But i fill confused with the first method.Can you explain for me more specifically? when the size of pixmap is in line with the size of the qgraphicsItem, while update the pixmap whether the qgraphicsItem will also being updated?

i'm looking forwad to hearing from you soonly.

christina123y
9th April 2009, 04:15
I am having the same problem, that the QGraphicsItem will do unnecessary paint when the window lose/gain focus or on a mouse movement, even though there is no actual new exposure event occurring.

I think this is a bug that Qt should fix, rather than asking application developers to find a workaround...

hi, i have resolve this problem through the second method suggested by wysota. i called setCacheMode(QGraphicsItem::ItemCoordinateCache,QS ize(width(),height())) for the qgraphicsitem. you can have a try.

wysota
9th April 2009, 07:48
But i fill confused with the first method.Can you explain for me more specifically? when the size of pixmap is in line with the size of the qgraphicsItem, while update the pixmap whether the qgraphicsItem will also being updated?

The first method is more or less the same as the second one only that it is your responsibility to update the pixmap. The approach is described here in Qt Quarterly: http://doc.trolltech.com/qq/qq06-flicker-free.html#doublebuffering

Qt3 didn't have double buffering capabilities so it had to be emulated using a pixmap.

christina123y
9th April 2009, 08:20
The first method is more or less the same as the second one only that it is your responsibility to update the pixmap. The approach is described here in Qt Quarterly: http://doc.trolltech.com/qq/qq06-flicker-free.html#doublebuffering

Qt3 didn't have double buffering capabilities so it had to be emulated using a pixmap.

I have read the reference you provide for me. and i comprehand more about the first method you suggest. and i will have a try. Thank you. any success or question will go shares.

christina123y
10th April 2009, 08:11
The first method is more or less the same as the second one only that it is your responsibility to update the pixmap. The approach is described here in Qt Quarterly: http://doc.trolltech.com/qq/qq06-flicker-free.html#doublebuffering

Qt3 didn't have double buffering capabilities so it had to be emulated using a pixmap.

Hi, i still have a question about the second method you suggested me.

i use setCacheMode() function for my item. it really didn't make my item to repaint when the mouse move on it.
Howerver when i zoom in the item , and the zoom percentage is set larger ( such as 3) or when i zoom in the graph for more times , then when the mouse move on the item, my item now begin to repaint. and i have a try ,when my zoom in percentage is 1.4*1.4, then i zoom in for two times won't make my item to repaint, when i zoom in for one more time , my item begin to repaint when the mouse move on it.
i also have set the right size of setCacheMode() when the item is scaled, this means that setCacheMode(CacheMode mode,QSize size) 's size is the same size of my item's boundingRect.
why ?

......./
and now i have found that qt has set limit to the size of cache,the default settings is 1024 kilobytes. when my graph is zoom in larger than this (1M), it now begin to call paint() to repaint.
and i also have tried to set the QSize is 1M, but it still didn't work, and this make my graph distortion. how can i resolve this problem.
wish your help soon!
I'm very appreciate for your help!

wysota
10th April 2009, 08:49
Which cache mode did you use? The limit you mention is set on QPixmapCache. You can modify it using QPixmapCache::setCacheLimit().

christina123y
10th April 2009, 13:37
Which cache mode did you use? The limit you mention is set on QPixmapCache. You can modify it using QPixmapCache::setCacheLimit().

i use qgraphicsitem 's cache mode ----QGraphicsItem::ItemCoordinateCache.
this method really improve speed of drawing graph.
how can i resolve the problem i encountered(don't through setCacheLimit() , any other resolvent?). how can i use QGraphicsItem::setCacheMode() and when the graph is zoom in to some extent( then when the mouse move on this item, won't make my item to repaint ), but don't through setCacheLimit() , because anyway it seems unpratical.
wish your help again!
great thanks for your help!

wysota
10th April 2009, 15:38
I have trouble understanding you. What seems impractical? If you want the item to be cached you have to make sure it fits in the cache or you will either lose quality or speed. You can use the other cache mode - DeviceCoordinateCache, maybe that fits your usecase more than ItemCoordinateCache.

christina123y
11th April 2009, 06:46
I have trouble understanding you. What seems impractical? If you want the item to be cached you have to make sure it fits in the cache or you will either lose quality or speed. You can use the other cache mode - DeviceCoordinateCache, maybe that fits your usecase more than ItemCoordinateCache.

Hi, i have already tried DeviceCoordinateCache cache mode ,but it still didn't work for me.
And i have look up the other thread ---
http://www.qtcentre.org/forum/f-qtopia-qt-extended-14/t-painting-updates-16213.html
and i have tried setViewportUpdateMode(), still can't help for me.

and i fill puzzled with what you said on #4(Check the boundingRect() for both items. For instance using QRectF::intersects(). Just remember to map those rects to scene coordinates first. It's the bounding rects that may intersect, not the shapes themselves),
would this helpwith me?

or any other solutions to this problem? thank you

and when i zoom in the graph to some extent, the scrollbar on the qgraphicsview can be dragged very slowly., the graph is repainted , and there is serious time delay.

wysota
11th April 2009, 09:52
You have to be aware you can't reduce the number of repaints to zero. Eventually your items will have to be repainted. And preventing complex repaints doesn't cause any repaints to stop - the item is still repainted but from the cache and not using complex drawing mechanisms. But if the area covered by the item becomes very big, repainting from cache might get slow as well. Tell me why exactly DeviceCoordinateCache doesn't work for you and what was wrong in using ItemCoordinateCache. Also try setting the viewport of the view to QGLWidget so that hardware acceleration kicks in.

christina123y
11th April 2009, 10:24
You have to be aware you can't reduce the number of repaints to zero. Eventually your items will have to be repainted. And preventing complex repaints doesn't cause any repaints to stop - the item is still repainted but from the cache and not using complex drawing mechanisms. But if the area covered by the item becomes very big, repainting from cache might get slow as well. Tell me why exactly DeviceCoordinateCache doesn't work for you and what was wrong in using ItemCoordinateCache. Also try setting the viewport of the view to QGLWidget so that hardware acceleration kicks in.

First, the problem with ItemCoordinateCache mode is that --------when my item need to draw a large amount of data (such as hundreds of thousands points or millions points),this make my graph look very density, my item's boundingrect change as zoom in proportion, and i update cache with new graph(after scale), however, if i zoom in my graph to some extent(which make the size of graph is larger than the cache), then the cache's graph is unuseless , and when the mouse move on the item, the graph is repaint too slowly ,event i can't drag the scrollbar on the graphicsview.
and i can't set the size of cache absoluteness , because the data counts is uncertained (for this i also can't constraint the counts of zoom in ).

Second, i have tried DeviceCoordinateCache mode ,and the problem is the same as i use ItemCoordinateCache .

Third, i didn't catch what you say to set the viewport of the view to QGLWidget clealy.

and i know that it can't avoid repaint of item, what i need is just to enhance the speed of repaint when the mouse is move on the qgraphicsitem when the item is zoomed in to some extent.

most grateful for your reply.

wysota
11th April 2009, 11:03
First, the problem with ItemCoordinateCache mode is that --------when my item need to draw a large amount of data (such as hundreds of thousands points or millions points),this make my graph look very density,
This is the nature of your graph. You can modify the graph item to be composed of many smaller items each forming a cluster of points and you will immediately gain a speedup as only those clusters that are visible will be drawn.


my item's boundingrect change as zoom in proportion,
I don't think you should change your item's bounding rect when you zoom. It's not zooming anymore if you do and Graphics View won't be able to help you much with it.


however, if i zoom in my graph to some extent(which make the size of graph is larger than the cache), then the cache's graph is unuseless
Yes, that's why you have to increase the cache size. The item can't be redrawn out of thin air - either its verbatim copy has to be stored somewhere (like in the cache) and that uses up memory or it has to be redrawn everytime from scratch. There is no third way.


and when the mouse move on the item, the graph is repaint too slowly ,event i can't drag the scrollbar on the graphicsview.
Again, splitting your item into smaller pieces will give you significant speedup. You can also disable interactivity of the view by calling QGraphicsView::setInteractive(false) which should prevent your items from being repainted as a reaction to mouse events.


and i can't set the size of cache absoluteness , because the data counts is uncertained (for this i also can't constraint the counts of zoom in ).
I don't know how would you expect it to work then :) There is no "infinity" in computer language. The amount of memory is limited and once you go over the edge your application will start acting abnormally.


Third, i didn't catch what you say to set the viewport of the view to QGLWidget clealy.

myView->setViewport(new QGLWidget);


and i know that it can't avoid repaint of item, what i need is just to enhance the speed of repaint when the mouse is move on the qgraphicsitem when the item is zoomed in to some extent.
Split the item. You can control the extent of splitting by setting a minimum/maximum number of points per cluster. If you have a single item that is larger than the area of the viewport you can see in the view then the item has to be redrawn completely anyway - including all the points in the graph. Now if you split the graph into many items, only those clusters of points that are visible will have to be redrawn. This is a speedup you get practically for free, without any caching or anything. It's worth a shot.

christina123y
11th April 2009, 15:35
This is the nature of your graph. You can modify the graph item to be composed of many smaller items each forming a cluster of points and you will immediately gain a speedup as only those clusters that are visible will be drawn.

Again, splitting your item into smaller pieces will give you significant speedup. You can also disable interactivity of the view by calling QGraphicsView::setInteractive(false) which should prevent your items from being repainted as a reaction to mouse events.

Split the item. You can control the extent of splitting by setting a minimum/maximum number of points per cluster. If you have a single item that is larger than the area of the viewport you can see in the view then the item has to be redrawn completely anyway - including all the points in the graph. Now if you split the graph into many items, only those clusters of points that are visible will have to be redrawn. This is a speedup you get practically for free, without any caching or anything. It's worth a shot.


hi, extremely grateful for your so good suggestion. Originally, my design to draw all points in an item in view of it will be easy to operate. and if i splitter all the points to several items, i don't know how to put these items together!
now,according to your direction, my thought is : splitter QVector<QPointF> vector which stores all the points to several segment, and then draw each segment's points on an item, but how can i put these items together appropriately just to compose integrate and correct graph, this means how i know where to put these small items, and how can i map each segment points to corresponding item's coordinate.
And here is another question ,because when my application first start ,the whole graph is shown, and i splitter it to several items , when i zoom in , the graph is scaled, and how can i determin which items should be repainted(even i don't know after zooming in, which of these small items will be in the visible area), and if some points of a small item are in the visible area, other are not, then repaint? and if i zoom in the graph ,the items which are in the visible area , whether their boundingrect change as the zoom in proportions, or just use the QGraphicsItem::scale() to achieve this.
wish i has expressed clearly .
and looking forward to your reply again.
best appreciated to you.

wysota
11th April 2009, 16:30
Originally, my design to draw all points in an item in view of it will be easy to operate. and if i splitter all the points to several items, i don't know how to put these items together!
I'm not sure what you mean by putting them together. You can have an item that represents the background of the graph (axis, etc.) and have multiple items that are child items of the graph item representing the contents of the graph (points).


now,according to your direction, my thought is : splitter QVector<QPointF> vector which stores all the points to several segment, and then draw each segment's points on an item, but how can i put these items together appropriately just to compose integrate and correct graph, this means how i know where to put these small items, and how can i map each segment points to corresponding item's coordinate.
For splitting space usually an algorithm called BSP (binary space partitioning) is used. It splits the plane into two sub-planes and then splits each sub-plane again and again until it reaches the stop condition. GraphicsView uses that algorithm internally to quickly find items based on their geometry. If you decided to represent each point in the graph as separate item, you could automatically use that built-in mechanism but if you want to have clusters, you have to implement BSP yourself.


and how can i determin which items should be repainted
Qt does that for you. It will only repaint items that need repainting (i.e. those that are visible and have been marked as dirty).


A rule of a thumb is that if you have one item in the scene - you probably shouldn't be using QGraphicsView at all as it only adds to the complexity giving nothing in exchange. If you want to use Graphics View, have multiple items. Group them as you want using the parent-child relationship and squeeze as much from the architecture as possible.

If you only want a single item with zooming and scrolling, you'll get much better results with a custom widget derived from QAbstractScrollArea.

christina123y
12th April 2009, 13:26
I'm not sure what you mean by putting them together. You can have an item that represents the background of the graph (axis, etc.) and have multiple items that are child items of the graph item representing the contents of the graph (points).

today i have tried that each point as a child qgraphicsitem, and set a coordinate item as their parent, and it did draw correct graph. but, my points is larger then 12,0000
(they are float type ) ,i found ithat when i zoom in the graph to some extents it become slowly again,fairly slowly ,even make my application dead.


For splitting space usually an algorithm called BSP (binary space partitioning) is used. It splits the plane into two sub-planes and then splits each sub-plane again and again until it reaches the stop condition. GraphicsView uses that algorithm internally to quickly find items based on their geometry.

i have look up the reference of BSP , but it is still obscure to me.maybe i should spend some time to investigate this. would you please provide me some relative reference? thank you.


If you decided to represent each point in the graph as separate item, you could automatically use that built-in mechanism but if you want to have clusters, you have to implement BSP yourself.

what do you mean "automatically use that built-in mechanism "? i make each point as a separate item, and then use QGraphicsItem::setPos() in its parent item. how should i use
alleged built-in mechanism ? Or Qt does that itself? but why didn't this way improve the speed. and it still repaint very slowly.


A rule of a thumb is that if you have one item in the scene - you probably shouldn't be using QGraphicsView at all as it only adds to the complexity giving nothing in exchange. If you want to use Graphics View, have multiple items. Group them as you want using the parent-child relationship and squeeze as much from the architecture as possible.
If you only want a single item with zooming and scrolling, you'll get much better results with a custom widget derived from QAbstractScrollArea.

i use QGraphicsView for i need to make my application perform other functions such as mouse tracker, and so on. next time i will think over what frame or just qwidget to use.and with great thanks to your advice.and how to use BSP to achieve improving speed of repaint?

best wishes to you!

faldzip
12th April 2009, 15:49
I think you might take a closer look into "40000 chips" demo from Qt, but I'm not sure that it's what you want: http://doc.trolltech.com/4.5/demos-chip.html

wysota
14th April 2009, 21:41
today i have tried that each point as a child qgraphicsitem, and set a coordinate item as their parent, and it did draw correct graph. but, my points is larger then 12,0000
(they are float type ) ,i found ithat when i zoom in the graph to some extents it become slowly again,fairly slowly ,even make my application dead.
Zooming in should make your application faster not slower. You must have done something wrong.


i have look up the reference of BSP , but it is still obscure to me.maybe i should spend some time to investigate this. would you please provide me some relative reference? thank you.
It's a very popular algorithm. It's 3D version (based on octree) is used in most 3D FPP/TPP games to speed up rendering by cutting out objects that are not in the viewing frustum. I'm sure you'll find lots of materials on the subject.


what do you mean "automatically use that built-in mechanism "? i make each point as a separate item, and then use QGraphicsItem::setPos() in its parent item. how should i use
alleged built-in mechanism ? Or Qt does that itself?
If each point is a separate item then you already use this mechanism.


but why didn't this way improve the speed. and it still repaint very slowly.
I'd have to see the code. You can search the forum. Some time ago as a reply to one of Ini's complaints about QGraphicsView functionality I made a proof of concept and posted it here. As far as I remember the application contained 10k points in a form of zoomable graph. You can see an example implementation there.


i use QGraphicsView for i need to make my application perform other functions such as mouse tracker, and so on.
You can do the same with a regular widget. There is only one usecase currently where you'd want to use graphics view when having a single item and that's not your usecase.


and how to use BSP to achieve improving speed of repaint?

Group your points into clusters. This requires a bit of more computation power when preparing the graph but once it's there you should get a significant speedup. You can use the "K nearest neighbours" and/or "K-Means" algorithms for clustering. The first algorithm is a classification algorithm which can prove useful once you "teach" your graph the characteristics of your data. It will make it possible to quickly find the appropriate cluster for a new point. The second algorithm is a classical clustering algorithm.

christina123y
17th April 2009, 09:24
First ,thank you very much, these days, i have tried another way to improve the speed of repainting, but it still didn't resovle essential problem. now allow me to depict my method: I still draw all the points in a pixmap ,then draw pixmap to a single item, and draw coordinate system as the same way. when i zoom in the graph, i newly adjust the item's boundingRect with the corresponding proportion. and draw the whole points in the item.only when the item's width and height
overrun the range (the range within the cache mode--ItemCordinateCache can support), then repaint the graph, however,while the mouse move what i need to do is that to draw pixmap on the item. this really has improve the speed of repaint while mouse move.
wish i has explain my thought clearly.
but when zoom in the graph ,the first time to repaint the graph is still slow, and feels very very slowly when you move the scrollbar to see graph in the invisible area.
maybe i should look up other way for solution.


Zooming in should make your application faster not slower. You must have done something wrong..

i have checked out ,i really draw each point as a single item. but it really feels very slowly.



It's a very popular algorithm. It's 3D version (based on octree) is used in most 3D FPP/TPP games to speed up rendering by cutting out objects that are not in the viewing frustum. I'm sure you'll find lots of materials on the subject.
hn,i have looked up some reference on it, and i found it very hard, and i still didn't know to to apply to my application. these days , i have given up on this solution, but my solution still didn't works well, maybe i should penetrate into this method.



I'd have to see the code. You can search the forum. Some time ago as a reply to one of Ini's complaints about QGraphicsView functionality I made a proof of concept and posted it here. As far as I remember the application contained 10k points in a form of zoomable graph. You can see an example implementation there.

Could you please show me the URL where you post it and the example , i haven't found it , thank you.

best wishes to you. and looking forward to your reply.

wysota
17th April 2009, 11:17
however,while the mouse move what i need to do is that to draw pixmap on the item. this really has improve the speed of repaint while mouse move.
That's the first solution I described. And caching works exactly the same way only that it does the bookkeeping itself without you having to care.


but when zoom in the graph ,the first time to repaint the graph is still slow,
and feels very very slowly when you move the scrollbar to see graph in the invisible area.
maybe i should look up other way for solution.
This is because you have a single item - the whole pixmap has to be regenerated and rendered onto the viewport although only a part of it is visible.


i have checked out ,i really draw each point as a single item. but it really feels very slowly.
Zooming should reduce the number of paint operations. If it doesn't (or if it increases it) then there is something wrong with your code.


hn,i have looked up some reference on it, and i found it very hard, and i still didn't know to to apply to my application. these days , i have given up on this solution, but my solution still didn't works well, maybe i should penetrate into this method.
It's not that hard, the algorithm is very simple. The only thing is that you have to know why you are doing things you are doing and not just because some fool on QtCentre forum told you to do it :)


Could you please show me the URL where you post it and the example , i haven't found it , thank you.
It's here somewhere. Use the search facilities of the forum to search through threads started by the user I mentioned before.