0

I wanted to use openGL to render QGraphicsview items so that I can save CPU power. In the documentation it states that what I have to do is add a QOpenGLWidget as the view port of the QGraphicsview. This is what I'm doing:

QOpenGLWidget *glWidget = new QOpenGLWidget();
ui->drawScreen->setViewport(glWidget);
ui->drawScreen->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
ui->drawScreen->update();

(ui->drawScreen is my QgraphicsView)

When I draw something on the screen it draws correctly but after a certain time I want to remove the item with a fade animation. That isn't provoking the screen to update, i.e., when I do this:

double opacity = 1.0 - ((elapsed - annotationFrameOut) / (double)fadeOutFrames);
(*i)->setOpacity(opacity);

(*i) is one item.

Or this:

scene.removeItem(item);

Visually, nothing happens. Only when I re-size the screen does the item disappear, or show the correct opacity in case it's fading.

Also, when I move an item no position disappears so it creates a dragging effect. Same for the selection rectangle or when typing in a text item (the bounding rect is drawn multiple times).

This seems like a simple update problem but I can't figure out what to do, nor do I seem to find this issue online. I am using Windows.

Thank you for your time.

EDIT: Picture exemplifying the problem. Blue rectangles are the selection rectangles that are never removed (unless I re-size the window) Blue rectangles are the selection rectangle that is never removed (unless I re-size the window)

EDIT 2: Code using QGLWidget

QGLWidget *viewPort = new QGLWidget(QGLFormat(QGL::SampleBuffers | QGL::AlphaChannel), ui->drawScreen);

ui->drawScreen->setViewport(viewPort);
ui->drawScreen->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
ui->drawScreen->update();

EDIT 3: In my app I have a video playing bellow the QGraphicsView. I show the video by updating a QLabel every time a new frame comes up.

Instead of using a QLabel I tried to update the QPixmap of a QGraphicsPixmapImage. If now I draw on top of this image the drawing is being correctly refreshed, I guess because the picture is being updated constantly. But outside of the picture it still doesn't work.

Solidus
  • 698
  • 1
  • 9
  • 23
  • It looks like you're not updating your window. Have you tried calling the function 'update()'? It's a function that's part of QOpenGLWidget inherited from QWidget. Call the function in your paintGL() or wherever you update the main loop of your program. – Poriferous Jul 27 '15 at 17:30
  • I have extended the `QGraphicsView` class. Inside of it, I have a method that checks when the drawn items should be erased (based on frames from a video). In there I have tried to do `viewport()->update()` or call the view's `update()` but it isn't working. Without `openGL` this works well (even without that call). Do I have to extend the `QOpenGLWidget` and implement my own `paintGL`? It seems that not only my operations, but anything that means removing a drawn item does not update (e.g. selection rectangle). – Solidus Jul 27 '15 at 17:59
  • I have added a picture to help illustrate this. – Solidus Jul 27 '15 at 18:04
  • Call QOpenGLWidget's update() function. In all honesty you should draw up a class diagram and decide whether you want to inherit from QOPenGLWidget or not. For what it's worth, you are mixing two rendering APIs together. At this point, you'd have to ask yourself whether it's worth going down the low-level lane of OpenGL (not a bad thing at all) is worth it or not. For just to shed some CPU power, I say go with Graphics View and not try to get the GPU to render it. – Poriferous Jul 27 '15 at 19:03
  • @Poriferous The advice to manually call `update()` is wrong. The whole point of using `QGraphicsView` is that such things are handled automatically. Your comment about "mixing" two rendering APIs is wrong too - Qt fully supports using `QPainter` on an OpenGL context. This is supposed to work, and indeed it did work with the old `QGLWidget`. – Kuba hasn't forgotten Monica Jul 27 '15 at 20:36
  • I understand that; but from a programmatic point of view it's not viable to mix `QGraphicsView` and `QOpenGLWidget` together. What might be pursued by the OP in `QGraphicsView` can very much be done with OpenGL. Even rendering text and rectangles. That's the end of my argument though since this isn't the place to debate program schematics. – Poriferous Jul 27 '15 at 21:26
  • The reason I wanted to use the `GPU` for the `QGraphicsview` is because I am playing a video, or taking a live record via webcam behind it. Which is already a fair amount of `CPU` usage. Unfortunately I am too deep into the `QGraphicsView` and use a lot of its functionality to be able to simple switch back to create my own `QGraphicsView` with `openGL`. – Solidus Jul 28 '15 at 13:43
  • This will never work: the view's viewport is a GL insert, so you can't have any widgets underneath it, they won't show. You need to simply change the entire widget to be a `QOpenGLWidget` (*not* `QGLWidget`), and things should work fine. – Kuba hasn't forgotten Monica Jul 28 '15 at 15:47
  • > from a programmatic point of view it's not viable to mix QGraphicsView and QOpenGLWidget together. the QOpenGLWidget doc explicitely states that this is something possible: "[...] when being used as a viewport for other widgets like QGraphicsView." – Jean-Michaël Celerier Nov 16 '16 at 11:55

3 Answers3

1

The explicit update() call is unnecessary. This looks like a Qt bug. The QGraphicsView does some magic to a QGLWidget to make it work as a viewport. Most likely, this magic hasn't been ported to work with QOpenGLWidget.

As a workaround, use QGLWidget instead.

Community
  • 1
  • 1
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • I tried using `QGLWidget` and got the same results. I am using QT5.5, could this be a problem with this version? – Solidus Jul 28 '15 at 13:40
  • @Solidus Try with previous versions, then. – Kuba hasn't forgotten Monica Jul 28 '15 at 14:22
  • Something interesting. I created a different project to serve as a simple example. I basically just created a `QGraphicsView`, a `QGraphicsScene` and added one button to add a text item and one button to remove it. I made the view's viewport a `QGLWidget` and it works well. Could this be related to my view being a inherited class? Also, in my project, when I use `openGL`, the background turns black. In this small example it stays white. EDIT: The background being black is because I had my view transparent. It still works well with that in my example though, so that's not the problem. – Solidus Jul 28 '15 at 14:51
  • I seem to have found the problem and I posted it as an answer. If you have any idea why that causes this problem, I'd love to hear your explanation. :) Thanks for the help. – Solidus Jul 28 '15 at 15:19
  • Sorry, I guess I jumped the gun too soon, it still doesn't work every time. I have edited my question with what happened. – Solidus Jul 28 '15 at 15:32
  • Ok, now I think I figure out the problem. The problem seesm to be with adding a stylesheet to the QGraphicsView (or its container widget). Every time I add a stylesheet the background turns black and the refresh stops working as expected. Is this a bug? How can I changes the background-color and remove the border without the stylesheets? – Solidus Jul 28 '15 at 16:08
  • @Solidus It may be a bug. Don't use the stylesheets. The background can be made whatever you want by reimplementing the `drawBackground` on either the scene or the view. I don't know what border are you talking about. – Kuba hasn't forgotten Monica Jul 28 '15 at 16:14
  • By default the `QGraphicsView` has a border, from a `QFrame` it inherits. I figured out how to remove it. Thanks for all the help. I'll add these conclusions as an answer and maybe post the bug to QT. – Solidus Jul 28 '15 at 16:24
  • It seems that `QOpenGLWidget` also has another bug. Every time something goes on top of it the background just returns to white. With `QGLWidget` this doesn't seem to happen. – Solidus Jul 28 '15 at 17:47
  • @Solidus What do you mean by "on top of it"? By the way, it's a bad idea to have a partial `QOpenGLWidget`. Why won't you use that widget as the base widget that all the others sit on? – Kuba hasn't forgotten Monica Jul 28 '15 at 17:48
  • For example, I have buttons that popup small menus next to them (which are widgets). Or when I hover those buttons they have a small highlight which increases their size and they go on top of the `QGraphicsView` (which now has a `QOpenGLWidget` as the view-port). When any of these things happen the background goes back to white. I've made a small test that reproduces this in which I put a widget on top of the view and click a button to show/hide it. What do you mean have a partial `QOpenGLWidget`? – Solidus Jul 28 '15 at 18:02
  • @Solidus Your `QGraphicsView` is a child of some other widget, and the ultimate root of that hierarchy could simply be a `QOpenGLWidget` itself. You then wouldn't need to know about the viewport of the `QGraphicsView` in particular. – Kuba hasn't forgotten Monica Jul 28 '15 at 18:13
  • My app has a `QMainWindow` which has several `QWidgets` for different areas of the UI, including a `QWidget` that has the `QGraphicsView`. What you mean is having a `QOpenGLWidget` to house all of those "containers"? I won't need to make the viewport of `QGraphicsView` `opengl` that way? – Solidus Jul 29 '15 at 11:13
  • @Solidus Make the `QMainWindow` a child of `QOpenGLWidget` and see what transpires. You'll of course need a layout in the gl widget, and will need to set its margins to zero. – Kuba hasn't forgotten Monica Jul 29 '15 at 12:49
  • It would not run if `QOpenGLWidget` is the parent of `QMainWindow` but I managed to make `QOpenGLWidget` as the central widget with `setCentralWidget`. I had to then make every widget container a child of the opengl. It seems to be working. Does this mean everything is being rendered with the GPU? I still notice a big CPU spike with the drawing and video playing at the same time, so I don't see a big improvement in doing this. Maybe I'm doing something wrong? Or the spike does not come from the drawing itself but the computing of items. – Solidus Jul 29 '15 at 16:00
  • @Solidus That I don't know. It may be that the rendering is not done using the GPU, but using the raster engine, unfortunately. I think that replacing the viewport of a `QGraphicsView` is a special case that is handled differently. Sorry for the noise. – Kuba hasn't forgotten Monica Jul 29 '15 at 20:39
  • No problem at all!! I will try to investigate further into this. Thank you very much for all the help you provided! – Solidus Jul 30 '15 at 11:41
1

It seems the problem lies with the stylesheet I used to change the background color of the view. Adding a stylesheet to the widget also produces the same bug. With a stylesheet the view-port just becomes black and the refresh of items doesn't seem to work properly.

I removed the stylesheet and changed the background-color by re-implementing the drawBackground function.

Thanks to Kuba Ober for helping me figure out this.

Solidus
  • 698
  • 1
  • 9
  • 23
0

In some way the stylesheet generate a repaint bug, even in my case I have removed the stylesheet and everything works correctly.

Robert
  • 5,278
  • 43
  • 65
  • 115
df80
  • 11
  • 1