QWidget with graphicseffect and render method
-
I've got problem when using QWidget::render method to draw widget to pixmap.
If QWidget has no graphicseffect, then everething is ok.
But if I apply graphicseffect (QGraphicsDropShadowEffect), then QWidget::render draws nothing.
I have to call QWidget::graphicsEffect()::setEnabled(false), then QWidget::render, then QWidget::graphicsEffect()::setEnabled(true).
Is there a way to use QWidget::render with graphicseffect, without turning it off? Or any clues to find out root cause of my problem?
Qt 5.15, windows environment. -
@denistu Hi
You can use QScreen::grabWindow()QGuiApplication::primaryScreen()->grabWindow(winId()).save("screenScreenshot.png");
From QScreen::grabWindow() documentation:
The grabWindow() function grabs pixels from the screen, not from the window, i.e. if there is another window partially or entirely over the one you grab, you get pixels from the overlying window, too.
https://doc.qt.io/qt-6/qscreen.html#grabWindow -
@denistu
After I read the source code, I found that when a widget with QGraphicsEffect executes the render method, the internal call to QGraphicsEffect's draw method will call the sourceWidget's render method again. However, there's an internal judgment in the render method that causes the sourceWidget to return. So, you can see that using the target widget's render method directly doesn't work. So, all we have to do is figure out a way to call the widget's render method indirectly.We can set a container widget as the parent widget for the widget and just call the container widget's render method. That'll execute the render methods of all child widgets.I hope this helps.void QWidget::render(QPainter *painter, const QPoint &targetOffset, const QRegion &sourceRegion, RenderFlags renderFlags) { .... Q_D(QWidget); const bool inRenderWithPainter = d->extra && d->extra->inRenderWithPainter; const QRegion toBePainted = !inRenderWithPainter ? d->prepareToRender(sourceRegion, renderFlags) : sourceRegion; if (toBePainted.isEmpty()) return; if (!d->extra) d->createExtra(); d->extra->inRenderWithPainter = true; .... }
https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/kernel/qwidget.cpp#n5316
QPixmap QWidgetEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset, QGraphicsEffect::PixmapPadMode mode) const { .... // call render() again, so would retrun and the pixmap is only transpant with nothings. m_widget->render(&pixmap, pixmapOffset, QRegion(), QWidget::DrawChildren); .... }
https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/kernel/qwidget.cpp#n6040