Important: Please read the Qt Code of Conduct -

Fixed Content on QGraphicsview

  • Hi,
    I am trying to paint some extra content on top of my custom GraphicsView. The goal is to have a Vignette-Effect over the displayed Scene. Of course the overlay should be fixed to the View.


    What I tryed so far:

    • reimplementing drawForeground()
      - this solution would internally add new Items to the actual Scene. I would have to handle this special Items for every transformation of the Scene to keep it static. (And I didn't really get it work properly)
      But especially I guess this is not the way Scenes, View and Items should be handled. It would be better not to mix Vignette-Items with Scene-Content.

    • reimplementing paintEvent()
      - maybe a bad idea: I tried to reimplement the paintEvent(), calling the parents paintEvent first to let it draw the Scene

    • Stylesheets
      - I dont have much experience with Stylesheets and I am not sure if it is even possible with a GraphicsView.
      In my case the stylesheet doesn't seem to have any effect, maybe because the Scene is drawn on top?

    • Another QWidget on top
      - this would be a really ugly hack

    Does someone have a (rough) idea, how to achieve that Effect?
    Is there a regular way of doing this?

    I am open for every hint, idea and suggestion.
    Thank you so much,

  • Lifetime Qt Champion

    @justStartedQt said in Fixed Content on QGraphicsview:


    Like the grey button like seen in your image ?
    Also behind any object Items?
    I googled Vignette-Effect and it seems to mean darken in the corners but
    is that what you mean ?

    I have never tried with stylesheet so i dont know if it stay fixed if you rotate the view
    but it does draw.
    alt text

    Seems to stay fixed
    alt text

  • Hi, thank you for the fast answer.
    My Picture was maybe not as good. I thought about a Border on top of the Scene/Items. The Gradient would be transparent in the inside and opaque outside. So the Scene/Items "disappear" when coming to the edges. I will just make another quick drawing. - Thanks

  • Lifetime Qt Champion

    ok so it must be in front/over the items.
    That rules out stylesheet as they are behind.
    So the items should sort of fade in the corners.

    Im reading about
    void setForegroundBrush(const QBrush & brush)
    maybe that can do it
    says gradient possible.

  • Lifetime Qt Champion

    foregroundBrush scales with the view so gradient would also
    alt text

  • The Picture for the sake of completeness:


    As far as I understand, the ForegroundBrush controlls only the behavior of the drawForeground-function. The function creates new content in the QGraphicsScene::ForegroundLayer instead of the ItemLayer. The same function can be accessed trough the Graphicsview.

  • Hi,
    is it maybe possible to reimplement QGraphicsView::paintEvent?
    I tryed to call the parent function first, to let it draw the Scene. But it seemed impossible to add a new QPainter/use the old one.
    Thank you for your efforts.

  • Lifetime Qt Champion

    I think
    GraphicsView::drawForeground(QPainter *painter, const QRectF &rect)
    is the best way but one issue is that the rect is the dirty rect and since
    view can be huge the fade effect should draw "just big enough" with outscaling.
    I wondering if one of the QGraphicsEffect can do it.

    Its clearly possible with
    alt text
    But we need some sort of translate or scaling to make it be static as it
    scales with the view.

  • Hi,
    I gave it a try:

    	vignetteLeftGradient = QLinearGradient(0, 0, VignetteWidth, 0); 
                                               // setting gradients coordinates
    	vignetteLeftGradient.setColorAt(0, QColor(0, 0, 255, 255));
    	vignetteLeftGradient.setColorAt(1, QColor(255, 0, 0, 255));
    	vignetteLeftBrush = QBrush(vignetteLeftGradient);
    void GraphicsView::drawForeground(QPainter *painter, const QRectF &rect)
    	painter->drawConvexPolygon(vignetteLeftPoints, 4);
    void GraphicsView::resizeEvent(QResizeEvent *event)
    void GraphicsView::recalcVignetteGeometry()
    	vignetteLeftPoints[0] = mapToScene(0, 0);
    	vignetteLeftPoints[1] = mapToScene(VignetteWidth, VignetteWidth);
    	vignetteLeftPoints[2] = mapToScene(VignetteWidth, height() - VignetteWidth);
    	vignetteLeftPoints[3] = mapToScene(0, height());

    The result:


    The gradient does not appear. I think there is a problem with setting the gradients position.
    Is the gradient part of the Scene and do I have to map it to Scene-Coordinates?
    Do I have to use another QGradient::CoordinateMode?

    The big disadvantage is maybe, that one has to manage all transformations manually.

  • Lifetime Qt Champion

    Im not sure how to get make it static.
    Seems to scale regards less of that i do.

    found it.
    alt text

    void GraphicsView::drawForeground(QPainter* painter, const QRectF& rect) {
      QRectF area ( mapToScene(viewport()->geometry()).boundingRect());
      QRadialGradient radialGrad(, area.width());
      radialGrad.setColorAt(0, Qt::white);
      radialGrad.setColorAt(0.5, Qt::green);
      radialGrad.setColorAt(1, Qt::black);
      painter->fillRect(area, radialGrad);

    Its not quite there i know but it wont scale with view and
    if you tweak the QRadialGradient it should work. ( i hope) :)

  • @mrjj


    It does work with resizing and hopefully also with SceneTransformations by simply calling recalcVignetteGeometry() again.

    For everyone who wants to do something similar:


    #ifndef GRAPHICSVIEW_H
    #define GRAPHICSVIEW_H
    #include <QGraphicsView>
    class GraphicsView : public QGraphicsView
    		void drawForeground(QPainter *painter, const QRectF &rect);
    		void resizeEvent(QResizeEvent *event);
    		void init();
    		// Vignette:
    		void recalcVignetteGeometry();
    		const int VignetteWidth = 50;
    		const QColor vInnerColor = QColor(22, 22, 22, 0);
    		const QColor vOuterColor = QColor(22, 22, 22, 255);
    		// -Left:
    		QPointF vLeftPoints[4];
    		QLinearGradient vLeftGradient;
    		// -Top:
    		QPointF vTopPoints[4];
    		QLinearGradient vTopGradient;
    		// -Right:
    		QPointF vRightPoints[4];
    		QLinearGradient vRightGradient;
    		// -Bottom:
    		QPointF vBottomPoints[4];
    		QLinearGradient vBottomGradient;
    #endif // GRAPHICSVIEW_H


    #include "graphicsview.h"
    	vLeftGradient.setColorAt(0, vOuterColor);
    	vLeftGradient.setColorAt(1, vInnerColor);
    	vTopGradient.setColorAt(0, vOuterColor);
    	vTopGradient.setColorAt(1, vInnerColor);
    	vRightGradient.setColorAt(0, vOuterColor);
    	vRightGradient.setColorAt(1, vInnerColor);
    	vBottomGradient.setColorAt(0, vOuterColor);
    	vBottomGradient.setColorAt(1, vInnerColor);
    void GraphicsView::drawForeground(QPainter *painter, const QRectF &rect)
    	// Left
    	QBrush vLeftBrush(vLeftGradient);
    	painter->drawConvexPolygon(vLeftPoints, 4);
    	// Top
    	QBrush vTopBrush(vTopGradient);
    	painter->drawConvexPolygon(vTopPoints, 4);
    	// Right
    	QBrush vRightBrush(vRightGradient);
    	painter->drawConvexPolygon(vRightPoints, 4);
    	// Bottom
    	QBrush vBottomBrush(vBottomGradient);
    	painter->drawConvexPolygon(vBottomPoints, 4);
    void GraphicsView::recalcVignetteGeometry()
    	// Left
    	vLeftPoints[0] = mapToScene(0, 0);
    	vLeftPoints[1] = mapToScene(VignetteWidth, VignetteWidth);
    	vLeftPoints[2] = mapToScene(VignetteWidth, height() - VignetteWidth);
    	vLeftPoints[3] = mapToScene(0, height());
    	vLeftGradient.setStart(mapToScene(0, 0).x(), 0);
    	vLeftGradient.setFinalStop(mapToScene(VignetteWidth, 0).x(), 0);
    	// Top
    	vTopPoints[0] = mapToScene(width(), 0);
    	vTopPoints[1] = mapToScene(width() - VignetteWidth, VignetteWidth);
    	vTopPoints[2] = mapToScene(VignetteWidth, VignetteWidth);
    	vTopPoints[3] = mapToScene(0, 0);
    	vTopGradient.setStart(0, mapToScene(0, 0).y());
    	vTopGradient.setFinalStop(0, mapToScene(0, VignetteWidth).y());
    	// Right
    	vRightPoints[0] = mapToScene(width(), height());
    	vRightPoints[1] = mapToScene(width() - VignetteWidth, height() - VignetteWidth);
    	vRightPoints[2] = mapToScene(width() - VignetteWidth, VignetteWidth);
    	vRightPoints[3] = mapToScene(width(), 0);
    	vRightGradient.setStart(mapToScene(width(), 0).x(), 0);
    	vRightGradient.setFinalStop(mapToScene(width() - VignetteWidth, 0).x(), 0);
    	// Bottom
    	vBottomPoints[0] = mapToScene(0, height());
    	vBottomPoints[1] = mapToScene(VignetteWidth, height() - VignetteWidth);
    	vBottomPoints[2] = mapToScene(width() - VignetteWidth, height() - VignetteWidth);
    	vBottomPoints[3] = mapToScene(width(), height());
    	vBottomGradient.setStart(0, mapToScene(0, height()).y());
    	vBottomGradient.setFinalStop(0, mapToScene(0, height() - VignetteWidth).y());
    void GraphicsView::resizeEvent(QResizeEvent *event)

    Thank you so much @mrjj !
    You are definitely my Champion of the Year,

  • Lifetime Qt Champion


    Super Good work ! \o/
    Thank you for posting code.
    Hehe thank you. If i do not win this year, its a good comfort :)

Log in to reply