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,
justStartedQt -
-
@justStartedQt said in Fixed Content on QGraphicsview:
Vignette-Effect
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.
Update:
Seems to stay fixed
-
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 -
@justStartedQt
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
http://doc.qt.io/qt-5/qgraphicsview.html#foregroundBrush-prop
says gradient possible. -
Hi
Nope
foregroundBrush scales with the view so gradient would also
-
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. -
@justStartedQt
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
drawForeground
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:GraphicsView::GraphicsView() { 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->setBrush(vignetteLeftBrush); painter->drawConvexPolygon(vignetteLeftPoints, 4); } void GraphicsView::resizeEvent(QResizeEvent *event) { recalcVignetteGeometry(); } 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.
-
@justStartedQt
Im not sure how to get make it static.
Seems to scale regards less of that i do.Update:
found it.
void GraphicsView::drawForeground(QPainter* painter, const QRectF& rect) { QRectF area ( mapToScene(viewport()->geometry()).boundingRect()); QRadialGradient radialGrad(area.center(), area.width()); radialGrad.setColorAt(0, Qt::white); radialGrad.setColorAt(0.5, Qt::green); radialGrad.setColorAt(1, Qt::black); painter->setOpacity(0.9); 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
I FINALLY GOT IT!It does work with resizing and hopefully also with SceneTransformations by simply calling recalcVignetteGeometry() again.
For everyone who wants to do something similar:
graphicsview.h
#ifndef GRAPHICSVIEW_H #define GRAPHICSVIEW_H #include <QGraphicsView> class GraphicsView : public QGraphicsView { public: GraphicsView(); void drawForeground(QPainter *painter, const QRectF &rect); void resizeEvent(QResizeEvent *event); void init(); private: // 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
graphicsview.cpp
#include "graphicsview.h" GraphicsView::GraphicsView() { setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 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) { painter->setPen(Qt::NoPen); // Left QBrush vLeftBrush(vLeftGradient); painter->setBrush(vLeftBrush); painter->drawConvexPolygon(vLeftPoints, 4); // Top QBrush vTopBrush(vTopGradient); painter->setBrush(vTopBrush); painter->drawConvexPolygon(vTopPoints, 4); // Right QBrush vRightBrush(vRightGradient); painter->setBrush(vRightBrush); painter->drawConvexPolygon(vRightPoints, 4); // Bottom QBrush vBottomBrush(vBottomGradient); painter->setBrush(vBottomBrush); 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) { recalcVignetteGeometry(); }
Thank you so much @mrjj !
You are definitely my Champion of the Year,
justStartedQt -
Super Good work ! \o/
Thank you for posting code.
Hehe thank you. If i do not win this year, its a good comfort :)