Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QGraphicsView doesn't repaint correctly after scrolling with overwritten paintEvent



  • I run into an issue and can't figure out what I'm doing wrong. I'm trying to show this overlay text in the bottom right corner of my view (yes, the 100% down there), the text is shown correctly as long as I don't scroll (resizing the whole widget seems to be ok). As soon as I scroll, I get those artifacts as if only a part of the area is repainted.

    Before Scrolling, ok:
    fba222c6-1ef7-4893-b6e1-7893d6578309-image.png

    After resizing the whole window, making the view smaller, ok:
    29a4844c-1222-4cb5-a8f9-b070f3f45aec-image.png

    Scrolling down, not so ok:
    f07e2313-f8fa-4c6b-a0c8-b8334e3d51da-image.png

    This is how I draw the text, nothing special.

    void AnnotationView::paintEvent(QPaintEvent *event)
    {
    	QGraphicsView::paintEvent(event);
    
    	auto viewPort = viewport();
    	if(viewPort != nullptr){
    		QPainter painter(viewPort);
    		auto rect = event->rect().adjusted(0, 0, -2, -2);
    		auto alignment = Qt::AlignRight | Qt::AlignBottom;
    		auto value = qRound(mAnnotationViewZoomer->zoomValue() * 100);
    		auto text = QString::number(value) + QLatin1Literal("%");
    		painter.drawText(rect, alignment, text);
    	}
    }
    

    The paintEvent method seems to be called even when scrolling but the result doesn't seem to be correct.

    Any ideas what I'm dong wrong?


  • Lifetime Qt Champion

    Hi
    You can also try setting
    ViewportUpdateMode to FullViewportUpdate for test.
    Default is MinimalViewportUpdate


  • Lifetime Qt Champion

    event->rect() returns the changed rect/ the rect to redraw, not the rect of the viewport.



  • @Christian-Ehrlicher said in QGraphicsView doesn't repaint correctly after scrolling with overwritten paintEvent:

    event->rect() returns the changed rect/ the rect to redraw, not the rect of the viewport.

    What would be the proper way to do id? Do I need to the the view to repaint the full ViewPort rect when scroll is happening?


  • Lifetime Qt Champion

    You should paint at the correct position instead the lower right corner of a rect which should be currently updated. This rect just informs you where painting is needed, you use it to place your text.



  • @Christian-Ehrlicher said in QGraphicsView doesn't repaint correctly after scrolling with overwritten paintEvent:

    You should paint at the correct position instead the lower right corner of a rect which should be currently updated. This rect just informs you where painting is needed, you use it to place your text.

    This means that this here should be working, right? I'm painting in the lower right corner of the view port rect, that should be the whole thing? But it behaves the same:

    void AnnotationView::paintEvent(QPaintEvent *event)
    {
    	QGraphicsView::paintEvent(event);
    
    	auto viewPort = viewport();
    	if(viewPort != nullptr){
    		QPainter painter(viewPort);
    		auto rect = viewPort->rect().adjusted(0, 0, -2, -2);
    		auto alignment = Qt::AlignRight | Qt::AlignBottom;
    		auto value = qRound(mAnnotationViewZoomer->zoomValue() * 100);
    		auto text = QString::number(value) + QLatin1Literal("%");
    		painter.drawText(rect, alignment, text);
    	}
    }
    

    Or how else can I get the bottom right corner of the viewport?


  • Lifetime Qt Champion

    @dporobic I would guess yes, simply try it out.



  • @Christian-Ehrlicher said in QGraphicsView doesn't repaint correctly after scrolling with overwritten paintEvent:

    @dporobic I would guess yes, simply try it out.

    I have tried it out, even before I have posted here (and now again) and the result was the same, that's why I assumed the rect from viewport and event are the same.

    Here how it looks like:
    7dc1e9b3-426d-45ba-aaf1-71e80b55f746-image.png


  • Lifetime Qt Champion

    Did you print the coordinates of the rect? Please provide a minimal, compilable example.



  • @Christian-Ehrlicher said in QGraphicsView doesn't repaint correctly after scrolling with overwritten paintEvent:

    Did you print the coordinates of the rect?

    Following code:

    void AnnotationView::paintEvent(QPaintEvent *event)
    {
    	QGraphicsView::paintEvent(event);
    
    	auto viewPort = viewport();
    	if(viewPort != nullptr){
    		QPainter painter(viewPort);
    		auto rect = viewPort->rect().adjusted(0, 0, -2, -2);
    		auto rect2 = event->rect();
    		qDebug("ViewPort -> x: %s, y: %s, w: %s, h: %s", qPrintable(QString::number(rect.x())), qPrintable(QString::number(rect.y())), qPrintable(QString::number(rect.width())), qPrintable(QString::number(rect.height())));
    		qDebug("Event -> x: %s, y: %s, w: %s, h: %s", qPrintable(QString::number(rect2.x())), qPrintable(QString::number(rect2.y())), qPrintable(QString::number(rect2.width())), qPrintable(QString::number(rect2.height())));
    		auto alignment = Qt::AlignRight | Qt::AlignBottom;
    		auto value = qRound(mAnnotationViewZoomer->zoomValue() * 100);
    		auto text = QString::number(value) + QLatin1Literal("%");
    		painter.drawText(rect, alignment, text);
    	}
    }
    

    Gives me this output when scrolling to the bottom, as you said, the rects are not the same (those are the last four entires):

    ...
    ViewPort -> x: 0, y: 0, w: 288, h: 229
    Event -> x: 0, y: 224, w: 290, h: 7
    ViewPort -> x: 0, y: 0, w: 288, h: 229
    Event -> x: 0, y: 228, w: 290, h: 3
    ViewPort -> x: 0, y: 0, w: 288, h: 229
    Event -> x: 0, y: 0, w: 290, h: 231
    ViewPort -> x: 0, y: 0, w: 288, h: 229
    Event -> x: 0, y: 0, w: 290, h: 231
    ViewPort -> x: 0, y: 0, w: 288, h: 229
    Event -> x: 0, y: 0, w: 290, h: 231
    

    And this is how the output looks like:
    2b4f5130-3c95-4ac5-8896-58bd5b2067d5-image.png

    @Christian-Ehrlicher said in QGraphicsView doesn't repaint correctly after scrolling with overwritten paintEvent:

    Please provide a minimal, compilable example.

    I can provide one later.


  • Moderators

    @dporobic what version of QT are you using, and can you try it against an other one (newer) ?



  • @J-Hilk said in QGraphicsView doesn't repaint correctly after scrolling with overwritten paintEvent:

    @dporobic what version of QT are you using, and can you try it against an other one (newer) ?

    I'm using 5.9.9 on a Windows machine. I can try later on my Linux which has 5.12.7.


  • Lifetime Qt Champion

    Since you want to paint on a region which needs no update according to the paint event I would suggest you to call update on the complete viewport to see if this helps - just for testing of course.
    Since the viewport is moving it's not a normal use case to paint something on a fixed (from the widget pov) position, therefore all the problems here.


  • Lifetime Qt Champion

    Hi
    You can also try setting
    ViewportUpdateMode to FullViewportUpdate for test.
    Default is MinimalViewportUpdate



  • @Christian-Ehrlicher said in QGraphicsView doesn't repaint correctly after scrolling with overwritten paintEvent:

    Since you want to paint on a region which needs no update according to the paint event I would suggest you to call update on the complete viewport to see if this helps - just for testing of course.
    Since the viewport is moving it's not a normal use case to paint something on a fixed (from the widget pov) position, therefore all the problems here.

    My View can be scrolled by dragging while holding down the middle mouse key, so that's where I put the repaint method:

    void AnnotationView::mouseMoveEvent(QMouseEvent *event)
    {
    	if(mIsDragging) {
    		qDebug("Scroll to");
    		scrollTo(event->pos());
    		qDebug("Repaint");
    		repaint(viewport()->rect());   // Here the repaint
    		return;
    	}
    	QGraphicsView::mouseMoveEvent(event);
    }
    
    void AnnotationView::scrollTo(const QPoint &pos)
    {
    	auto delta = pos - mLastPosition;
    	scrollByDelta(horizontalScrollBar(), delta.x());
    	scrollByDelta(verticalScrollBar(), delta.y());
    	mLastPosition = pos;
    }
    
    void AnnotationView::scrollByDelta(QScrollBar *scrollBar, int delta) const
    {
    	scrollBar->setValue(scrollBar->value() - delta);
    }
    

    This is the output that I get:

    ...
    ViewPort -> x: 0, y: 0, w: 288, h: 229
    Event -> x: 0, y: 230, w: 290, h: 1
    Scroll to
    Repaint
    ViewPort -> x: 0, y: 0, w: 288, h: 229
    Event -> x: 0, y: 230, w: 290, h: 1
    Scroll to
    Repaint
    Scroll to
    Repaint
    ViewPort -> x: 0, y: 0, w: 288, h: 229
    Event -> x: 0, y: 230, w: 290, h: 1
    Scroll to
    Repaint
    ViewPort -> x: 0, y: 0, w: 288, h: 229
    Event -> x: 0, y: 230, w: 290, h: 1
    Scroll to
    Repaint
    Scroll to
    Repaint
    ViewPort -> x: 0, y: 0, w: 288, h: 229
    Event -> x: 0, y: 230, w: 290, h: 1
    Scroll to
    Repaint
    Scroll to
    Repaint
    ViewPort -> x: 0, y: 0, w: 288, h: 229
    Event -> x: 0, y: 230, w: 290, h: 1
    

    This is how it looks like in the application (the red arrow shows the direction of dragging):
    3c64554c-de2e-41af-9cf3-59de09c0aaf6-image.png

    When I do a single click on the view (where the red dot is), everything is repainted correctly:
    53b99d88-bceb-4f40-a8f8-9cace41975ee-image.png

    Using update or repaint behaves the same, couldn't see any difference. Also same with passing the viewPort rect or calling them without parameter. I have also noticed that slowly dragging leaves less artifacts behind, almost non when you're really slow. Dragging fast leaves is like on the screenshot.



  • @mrjj said in QGraphicsView doesn't repaint correctly after scrolling with overwritten paintEvent:

    Hi
    You can also try setting
    ViewportUpdateMode to FullViewportUpdate for test.
    Default is MinimalViewportUpdate

    This works, the text is always written in the bottom right corner, no artifacts. I have also tested the other 4 mods, the FullViewportUpdate seems to be the only one working.
    Is this effecting the repainting of the underlying Scene?


  • Lifetime Qt Champion

    @dporobic
    Hi
    yes, it switches from partial/clever updating to full redraw.
    So it might have performance complications with a huge number of items.
    You can test with the 40000 example and see how much/if it matters.
    https://doc.qt.io/qt-5/qtwidgets-graphicsview-chip-example.html


Log in to reply