Perfomance problems with a subclassed QGraphicsView
-
Greetings!
I have subclassed a QGraphicsView so that I can use it in QMainWindow::setCentralWidget() and add some custom implementations.
Now, I am getting some performance problems:
Flickering - the scene needs to update for a specific interval (fast! like realtime) and handles a lot of items (hundreds of it!). This problem is observable when there are too many items to handle or it is too fast.
Disappearing items - most of the items animate which means that it goes in and out of the QGraphicsView::sceneRect(). After it goes "outside", the item should return but it becomes "invisible" (i use qDebug to show the items location, and it is right inside the sceneRect). It is certainly NOT a problem of the QGraphicsItem. When I zoom out, the item "repaints" correctly.
ScrollBars where SET as hidden but they still show a light gray strip on the right and bottom of the widget
Cannot test is debug mode (in QtC) since it outputs the following "dirtySceneTransform" problem
@ASSERT: "!parent->d_ptr->dirtySceneTransform" in file graphicsview\qgraphicsitem.cpp, line 1043
ASSERT: "calledEmitUpdated" in file graphicsview\qgraphicsscene.cpp, line 481@I did some optimizations that I know of like removing antialiasing, using NoIndex, etc. but getting problems when there are too many items to handle.
I need a "perfect" guide in QGraphicsView optimizations and "right way" of subclassing it. Thanks!
PS: If you want to know what I am talking about, you may visit my project at "QBox2D-Github":https://github.com/Code-ReaQtor/QBox2D
or download "QTestBed":https://www.dropbox.com/s/evvbyfr4a1ryxxf/QTestbed.exe built under Qt4.8.4/msvc2012
try to zoom in/out or drag the scene while executing a test
also you may want to test "Tiles" while "Warm Starting" is unchecked then moving the window :( -
Andre, these are the codes I used for the subclassed QGraphicsView, the codes are generated by QtC. I only added some codes for optimizations but I don't think they are enough
@//qbox2dview.h
class QBox2DView : public QGraphicsView
{
Q_OBJECT
public:
explicit QBox2DView(QWidget *parent = 0);public slots:
signals:
private:
};@
@//qbox2dview.cpp
QBox2DView::QBox2DView(QWidget *parent) :
QGraphicsView(parent)
{
setTransformationAnchor(AnchorUnderMouse);
setDragMode(ScrollHandDrag);
setViewportUpdateMode(FullViewportUpdate);
setOptimizationFlag(DontSavePainterState);
setResizeAnchor(AnchorViewCenter);
//setRenderHint(QPainter::Antialiasing);horizontalScrollBar()->setHidden(true); //still shows a lightgray strip on the bottom verticalScrollBar()->setHidden(true); //still shows a lightgray strip on the right side setInteractive(true);
}@
I already solved some parts of my problem:
Disappearing items - calling "update" at a fast rate is "BAD". I Already solved with another approach
I am still getting some performance problems when there are "too many items" shown in the screen.
The whole window cannot be moved freely on the desktop, the mouse often locks up inside the app's boundaries.
Unhidden "scrollbars".
Some links about QGraphicsView optimizations might also be helpful
-
Why this:
setViewportUpdateMode(FullViewportUpdate);It means the whole view needs to redraw every time even one item changes. That is almost bound to lead to flickering.
Remember that the QGraphicsView framework is NOT hardware accelerated.
You also should be careful about QGraphicsView::DontSavePainterState. If even one of your item messes up and "forgets" to reset painter state, it's bound to produce artifacts.
Some general tuning hints:
- Use QStyleOptionGraphicsItem::levelOfDetailFromTransform to avoid painting things that the user won't be able to see anyway. See the 40000 chips demo for an example.
- Cache boundingRect() and shape() of your items, they are called often.
- Cache complex drawing operations into a QPixmap, or use setCacheMode on items where the content changes rarely, but is painted often
- Reimplement the opaqueArea() of your items, especially if items often wholly obscure other items.
- Avoid the following features: Gradients (cache them!), Alpha blending, QGraphicsProxyWidget
- Do not add / remove items too often. Rather, hide and re-use them.
-
@Asperamanca, thanks! That solved (partly) most of the problems!
However, the "hidden scrollbar" issue is still not solved. They still exists on the sides (right and bottom) as light gray strips and are actually blocking mouse inputs into the view.
-
If you use a plain QGraphicsView, and just remove the scroll bars, does it work then? (In the cases where I didn't need a scrollbar, I never had an issue).
If so, it would look like you unintentionally broke something when subclassing it.
-
[quote author="Asperamanca" date="1364330899"]If you use a plain QGraphicsView, and just remove the scroll bars, does it work then? (In the cases where I didn't need a scrollbar, I never had an issue).
If so, it would look like you unintentionally broke something when subclassing it.[/quote]
I just tried it and it is still there. Could it be a bug? I am using Qt 4.8.4
-
It could be a bug, of course. I am stuck at 4.8.1, so I couldn't say whether this might be something specific to 4.8.4, or whether you are doing something special that confuses GraphicsView.
You might want to check the "Qt issue navigator":https://bugreports.qt-project.org/secure/IssueNavigator.jspa
You could also post a new bug there. If possible, a small sample reproducing the problem would be helpful. The small sample might also help you find a workaround: If you try to reproduce the effect with a small sample, and everything works there, you might get an idea what might cause it. I know it's a bit of a long shot, but all I can think of right now.One problem with reporting a bug is that you can't expect help quickly that way. GraphicsView has no real maintainer (at least that was the case last November when I talked it over on the Developer Days).