QGraphcisView with QOpenGlWidget not updating properly on resize and scroll
-
wrote on 28 Aug 2021, 10:05 last edited by
I have QScrollArea, which has a QWidget, which has a QGraphicsView with QOpenGLWidget set as a viewport. The GraphicsView contains QGraphicsItems which are also custom and draw QPixmaps in their paint function. The problem is that when I programmatically change the scroll position of the QScrollArea or resize the window, the GraphicItems which are left out of the visible viewport of QScrollArea don't update when they become visible again, unless I hover them with the mouse.
Resize down:
Resize up back again:
After hovering with the mouse:
The problem arises only when I use QOpenGlWidget as a viewport, so I guess there is some miscommunication between the viewport of the QScrollArea and that of the GraphicsView. I've tried everything - from calling update() manually on QGraphicsView to setting all sorts of options like FullViewportUpdate, but nothing seems to work. The GraphicsView and its parent widget are heavy objects and I'm emulating a QTabWIdget, by using TabBar, which just sets the parameters of different "tab instances" (including the QScrollArea scroll bars position) onto a single view, creating the illusion of different opened widgets.
-
wrote on 28 Aug 2021, 10:30 last edited by Hristo KonstantinovThis post is deleted!
-
wrote on 28 Aug 2021, 11:19 last edited by
A code snippet from my custom GraphicsView constructor:
GraphicsView::GraphicsView(QWidget *parent) : QGraphicsView(parent), gl{nullptr}{ setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); setCacheMode(QGraphicsView::CacheBackground); setDragMode(QGraphicsView::RubberBandDrag); setViewportUpdateMode(QGraphicsView::FullViewportUpdate); gl = new QOpenGLWidget(); QSurfaceFormat format; format.setSamples(4); gl->setFormat(format); setViewport(gl); gl->setUpdateBehavior( QOpenGLWidget::UpdateBehavior::NoPartialUpdate); }
-
Hi,
Out of curiosity, why do you have your QGraphicsView inside a QScrollArea ?
-
wrote on 28 Aug 2021, 19:09 last edited by Hristo KonstantinovThis post is deleted!
-
wrote on 28 Aug 2021, 19:18 last edited by Hristo Konstantinov
@SGaist My custom QWidget(which contains the graphic view) is inside of the QScrollArea, since it has dynamic changes in height, and usually is bigger then the monitor itself, so I need to scroll it's contents some how:
If there is any better way, which lets me get around the problem, I am open to suggestions
-
wrote on 28 Aug 2021, 23:37 last edited by Hristo Konstantinov
Okay guys, just tell me which function to call, to repaint the viewport of the QGraphicsView properly, by myself. I'll override every resize and every scroll event and call it there if I have to.
-
@SGaist My custom QWidget(which contains the graphic view) is inside of the QScrollArea, since it has dynamic changes in height, and usually is bigger then the monitor itself, so I need to scroll it's contents some how:
If there is any better way, which lets me get around the problem, I am open to suggestions
wrote on 28 Aug 2021, 23:44 last edited by@Hristo-Konstantinov What @SGaist points out is that it is unnecessary to place a QGraphicsView in a QScrollArea since they both inherit from QAbstractScrollArea so if the content is very large then scrollbars will appear
-
@Hristo-Konstantinov What @SGaist points out is that it is unnecessary to place a QGraphicsView in a QScrollArea since they both inherit from QAbstractScrollArea so if the content is very large then scrollbars will appear
wrote on 29 Aug 2021, 13:00 last edited by@eyllanesc QGraphicsView has a fixed size. It is a child of the custom widget, which is very large. So I need QScrollArea not for the graphicsview, but for the widget, which holds the graphicsview
-
Hum... that sounds like a bug lurking...
You wrote that you have that issue when resizing programmatically, can you show how you do that ?
-
wrote on 30 Aug 2021, 00:35 last edited by Hristo Konstantinov
ScrollPos TabView::getScrollPos() { return ScrollPos { ui.scrollArea->verticalScrollBar()->value(), ui.scrollArea->horizontalScrollBar()->value() }; } void TabView::setScrollPos(ScrollPos scrollPos) { ui.scrollArea->verticalScrollBar()->setValue(scrollPos.height); ui.scrollArea->horizontalScrollBar()->setValue(scrollPos.width); }
I'm saving the scroll position in a vector of custom structs each time new tab is selected, and when I select the older tab, the presenter calls setScrollPos with the ScrollPos struct as an argument. Nothing fancy. But even if I resize the application window from the ui, if the graphicsview goes out of the viewport of the QScrollArea, the graphicitems in it that are hidden "outside" of the app window, don't draw themselves automatically when shown again, unless I hover them with the mouse. Now the question is how the mouse triggers their repainting and makes them appear again? If I know what does mouse hovering does on QGraphicsView to initialize the QOpenGl viewport repaint, I can call this function when I have to.
-
Just to be sure I understand your architecture:
- you have a QTabBar
- on top of a QScrollArea
- inside of which you have a complex widget containing a QGraphicsView beside other widgets
Is that correct ?
-
Just to be sure I understand your architecture:
- you have a QTabBar
- on top of a QScrollArea
- inside of which you have a complex widget containing a QGraphicsView beside other widgets
Is that correct ?
wrote on 30 Aug 2021, 21:37 last edited by Hristo Konstantinov@SGaist Exactly. I don't want to use QTabWidget, because it creates a new Widget everytime a new tab is "opened", and my widget, which contains the graphicsview is heavy, so I just emulate that behavior. The view itself is always the same, placed inside the QScrollArea. The selected tab just sends signal to the presenter (I keep my business and QT logic separated via MVP), and that signal contains the index of the data (which is stored for each tab in a vector) and then the data is displayed on the widget, which is inside of the QScrollArea.
-
@SGaist Exactly. I don't want to use QTabWidget, because it creates a new Widget everytime a new tab is "opened", and my widget, which contains the graphicsview is heavy, so I just emulate that behavior. The view itself is always the same, placed inside the QScrollArea. The selected tab just sends signal to the presenter (I keep my business and QT logic separated via MVP), and that signal contains the index of the data (which is stored for each tab in a vector) and then the data is displayed on the widget, which is inside of the QScrollArea.
@Hristo-Konstantinov said in QGraphcisView with QOpenGlWidget not updating properly on resize and scroll:
I don't want to use QTabWidget, because it creates a new Widget everytime a new tab is "opened"
No, it does not create a widget every time a tab is selected, it shows the widget which was put on that tab.
-
@Hristo-Konstantinov said in QGraphcisView with QOpenGlWidget not updating properly on resize and scroll:
I don't want to use QTabWidget, because it creates a new Widget everytime a new tab is "opened"
No, it does not create a widget every time a tab is selected, it shows the widget which was put on that tab.
wrote on 31 Aug 2021, 18:29 last edited by Hristo Konstantinov@jsulm oh, you're right. So maybe the real reason was I had to take back ownership of the widget every time the tab was closed, so it wouldn't get destroyed. Have been writing this app ever since I started learning programming an year ago, and I can't remember all of my decisions, sorry.
1/15