Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Jitter artefacts when reimplementing drawForeground
Forum Updated to NodeBB v4.3 + New Features

Jitter artefacts when reimplementing drawForeground

Scheduled Pinned Locked Moved Solved General and Desktop
qgraphicsviewpaintermaptoscene
4 Posts 3 Posters 628 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    Another Qt Beginner
    wrote on last edited by Another Qt Beginner
    #1

    Hi,
    I'm subclassing QGraphicsView to create a simple widget that supports panning and zooming to cursor position (for now).
    I want to create a vignette like border around the view:

    vignette.png
    So I reimplemented drawForeground, but there are two things I can't find a reason for:

    The polygon I use for the left side isn't drawn where it is suposed to:

    init.png
    ... it fixes itself after the first zooming operation or resizing of the window:

    fine.png
    This might be caused by mapToScene, giving unexpected result (see the qDebug further down)
    But the zooming and resizing works really well. The Panning on the other hand does not. It creates some ugly jittering, repeating the vignette and causing both my cpu and gpu to complain:

    gifDebugging.gif

    mydview.h

    class MyView : public QGraphicsView
    {
    	Q_OBJECT
    public:
    	MyView(QWidget *parent = nullptr);
    	~MyView();
    private:
    	const int maxZoomStepsOut = 10;
    	const int maxZoomStepsIn = -15;
    	int actualZoomStep;
    	
    	// panning
    	void shift(qreal dx, qreal dy);
    	void shift(QPointF point);
    	
    	virtual void mouseMoveEvent(QMouseEvent *event) override;
    	virtual void mousePressEvent(QMouseEvent *event) override;
    	virtual void mouseReleaseEvent(QMouseEvent *event) override;
    	
    	bool isPanning;		// wether view is in a panning progress or not
    	QPoint panningStart;	// startpoint of panning
    	
    	// zooming
    	virtual void wheelEvent(QWheelEvent *event) override;
    	const double zoomFactor = 1.2;
    	
    	// reimplement Foreground for Vignette
    	void drawForeground(QPainter *painter, const QRectF &rect) override;
    	const int vignetteSize = 40;
    	
    	// rects to store widget-coords
    	QPoint *vignetteLeftWidgetPolygon = new QPoint[4];
    	
    	// rects mapped to scene-coords
    	QPointF *vignetteLeftPolygon = new QPointF[4];
    	
    	// initalizes first properties of vignette-items, which won't change
    	void initVignette();
    	
    	// update the rects in scene-coords
    	void updateVignetteSceneCoords();
    	
    	// update vignetteGeometry in widget-coords in case of resize event
    	void updateVignetteGeometry();
    	virtual void resizeEvent(QResizeEvent *event) override;
    };
    

    myview.cpp

    MyView::MyView(QWidget *parent)
    {
    	setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    	setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    	setRenderHint(QPainter::Antialiasing);
    	setResizeAnchor(AnchorViewCenter);
    	
    	actualZoomStep = 0;
    }
    
    void MyView::shift(qreal dx, qreal dy)
    {
    	horizontalScrollBar()->setValue(  horizontalScrollBar()->value() + dx  );
    	verticalScrollBar()->setValue(  verticalScrollBar()->value() + dy  );
    	
    	// remap Vignette coords to Scene
    	updateVignetteSceneCoords();
    }
    
    void MyView::mouseMoveEvent(QMouseEvent *event)
    {
    	if ( isPanning )
    	{	// shift the view
    		shift( -( event->x() - panningStart.x() ),
    		       -( event->y() - panningStart.y() )	);
    		panningStart.setX( event->x() );
    		panningStart.setY( event->y() );
    		return;
    	}
    }
    
    void MyView::mousePressEvent(QMouseEvent *event)
    {
    	if (event->button() == Qt::MiddleButton)
    	{
    		isPanning = true;
    		panningStart.setX(event->x());
    		panningStart.setY(event->y());
    		setCursor(Qt::ClosedHandCursor);
    		event->accept();
    		return;
    	}
    	event->ignore();
    }
    
    void MyView::mouseReleaseEvent(QMouseEvent *event)
    {
    	if (event->button() == Qt::MiddleButton)
    	{
    		isPanning = false;
    		setCursor(Qt::ArrowCursor);
    		event->accept();
    		return;
    	}
    	event->ignore();
    }
    
    void MyView::wheelEvent(QWheelEvent *event)
    {	// if zooming out
    	if (event->delta() < 0) {
    		// if transform is not already at maxZoomStepsOut
    		if (actualZoomStep < maxZoomStepsOut) {
    				
    				scale(1.0 / zoomFactor, 1.0 / zoomFactor);
    				
    				// shift the view, so that the position under 
    				// the ouse cursor stays the same
    				QPointF viewportCenter = viewport()->rect().center();
    				QPointF mousePos = event->position();
    				QPointF diffNow = mousePos - viewportCenter;
    				QPointF diffNext = diffNow * zoomFactor;
    				QPointF diffNowToNext = diffNow - diffNext;
    				actualZoomStep++;
    				
    				shift(diffNowToNext.x(), diffNowToNext.y());		
    		}
    	// if zooming in
    	} else {
    		// if transform is not already at maxZoomStepsIn
    		if (actualZoomStep > maxZoomStepsIn) {	
    		
    				scale(zoomFactor, zoomFactor);
    				
    				// shift the view, so that the position under 
    				// the ouse cursor stays the same
    				QPointF viewportCenter = viewport()->rect().center();
    				QPointF mousePos = event->position();
    				QPointF diffNow = mousePos - viewportCenter;
    				QPointF diffNext = diffNow / zoomFactor;
    				QPointF diffNowToNext = diffNow - diffNext;
    				actualZoomStep--;
    				
    				shift(diffNowToNext.x(), diffNowToNext.y());
    		}
    	}
    }
    
    void MyView::drawForeground(QPainter *painter, const QRectF &rect)
    {
    	painter->setPen(Qt::NoPen);
    	painter->setBrush( QBrush(Qt::gray) );
    	painter->drawPolygon( vignetteLeftPolygon, 4 );
    }
    
    void MyView::initVignette()
    {
    	// init vignetteRects in widget-coordinates
    	updateVignetteGeometry();
    }
    
    void MyView::updateVignetteGeometry() // in case of resize event
    {
    	// update Rects
    	vignetteLeftWidgetPolygon[0] = QPoint(0, 0);
    	vignetteLeftWidgetPolygon[1] = QPoint(vignetteSize, vignetteSize);
    	vignetteLeftWidgetPolygon[2] = QPoint(vignetteSize, height()-vignetteSize);
    	vignetteLeftWidgetPolygon[3] = QPoint(0, height());
    	
    	qDebug() << "\n";
    	qDebug() << "call inside geometry";
    	qDebug() << "Polygon-Widget:" << vignetteLeftWidgetPolygon[0];
    	qDebug() << "Polygon-Widget:" << vignetteLeftWidgetPolygon[1];
    	qDebug() << "Polygon-Widget:" << vignetteLeftWidgetPolygon[2];
    	qDebug() << "Polygon-Widget:" << vignetteLeftWidgetPolygon[3];	
    	
    	// always remap to scene-coords when updating geometry
    	updateVignetteSceneCoords();
    }
    
    void MyView::updateVignetteSceneCoords()
    {
    	// map gradients
    		
    	// map Polygons
    	vignetteLeftPolygon[0] = mapToScene( vignetteLeftWidgetPolygon[0] );
    	vignetteLeftPolygon[1] = mapToScene( vignetteLeftWidgetPolygon[1] );
    	vignetteLeftPolygon[2] = mapToScene( vignetteLeftWidgetPolygon[2] );
    	vignetteLeftPolygon[3] = mapToScene( vignetteLeftWidgetPolygon[3] );
    	
    	qDebug() << "\n";
    	qDebug() << "call inside sceneCoords";
    	qDebug() << "Polygon:" << vignetteLeftPolygon[0];
    	qDebug() << "Polygon:" << vignetteLeftPolygon[1];
    	qDebug() << "Polygon:" << vignetteLeftPolygon[2];
    	qDebug() << "Polygon:" << vignetteLeftPolygon[3];
    }
    
    void MyView::resizeEvent(QResizeEvent *event)
    {
    	updateVignetteGeometry();
    }
    

    qDebug output:

    call inside geometry
    Polygon-Widget: QPoint(0,0)
    Polygon-Widget: QPoint(40,40)
    Polygon-Widget: QPoint(40,560)
    Polygon-Widget: QPoint(0,600)
    call inside sceneCoords
    Polygon: QPointF(-1178,-119)
    Polygon: QPointF(-1138,-79)
    Polygon: QPointF(-1138,441)
    Polygon: QPointF(-1178,481)
    ------------------------------------------------
    call inside geometry
    Polygon-Widget: QPoint(0,0)
    Polygon-Widget: QPoint(40,40)
    Polygon-Widget: QPoint(40,560)
    Polygon-Widget: QPoint(0,600)
    call inside sceneCoords
    Polygon: QPointF(-1258,-179)
    Polygon: QPointF(-1218,-139)
    Polygon: QPointF(-1218,381)
    Polygon: QPointF(-1258,421)
    

    The Debugs are called first at initialization -> here mapToScene() gives weird results
    The 2nd call is when I manuallly rsize the window -> here mapToScene() works fine

    Some things I realized:

    • The zoom function uses shift() as well (to move the scene back to the mouse cursor), but that doesn't cause artifacts.
    • I guess drawForeground() doesn't delete it's items, drawing them on top of each other. That's why my cpu/gpu is running crazy, creating LOTS of items.
    • calling eraseRect() in drawForeground() first only deletes my scene items, the jittering stays.

    Thank you so much for any clues!

    I am on Windows 10 Education version 1803 OS build 17134.1184
    using Qt 5.14.0 and QtCreator 4.11.0

    PS: I created a complete new Project to isolate the problem, this is actually the second version of this thread. I hope this helps a bit.

    PPS: I reduced he code a little (Destructors, includes) and left out main.cpp, mainwindow.h and mainwindow.cpp as those are really short and straight forward in my case.
    But I will post them as well, if someone is interested.

    1 Reply Last reply
    1
    • A Another Qt Beginner

      @SGaist thanks for the advise

      mrjjM Offline
      mrjjM Offline
      mrjj
      Lifetime Qt Champion
      wrote on last edited by
      #4

      @Another-Qt-Beginner
      Hi
      Did you try setting
      https://doc.qt.io/qt-5/qgraphicsview.html#ViewportUpdateMode-enum
      to FullViewportUpdate to see if that reduces the issues.

      1 Reply Last reply
      2
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #2

        Hi,

        For people to be able to check more effectively, you should post a complete minimal compile example.

        You should also add which version of Windows you are developing for as well as Qt version you are using.

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        A 1 Reply Last reply
        1
        • SGaistS SGaist

          Hi,

          For people to be able to check more effectively, you should post a complete minimal compile example.

          You should also add which version of Windows you are developing for as well as Qt version you are using.

          A Offline
          A Offline
          Another Qt Beginner
          wrote on last edited by
          #3

          @SGaist thanks for the advise

          mrjjM 1 Reply Last reply
          0
          • A Another Qt Beginner

            @SGaist thanks for the advise

            mrjjM Offline
            mrjjM Offline
            mrjj
            Lifetime Qt Champion
            wrote on last edited by
            #4

            @Another-Qt-Beginner
            Hi
            Did you try setting
            https://doc.qt.io/qt-5/qgraphicsview.html#ViewportUpdateMode-enum
            to FullViewportUpdate to see if that reduces the issues.

            1 Reply Last reply
            2

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved