I have a QOpenGLWidget
that does some OpenGL rendering and some non-OpenGL rendering using a QPainter
. The widget looks OK but when I try to create a screenshot of the widget by rendering it into a QPixmap
, suddenly all effects that are painted using QPainter
disappear. Here is a minimal code sample to reproduce the issue:
#include <QApplication>
#include <qopenglwidget.h>
#include <qopenglfunctions.h>
#include <qpushbutton.h>
#include <QPainter>
class MainWidget : public QOpenGLWidget, QOpenGLFunctions{
public:
QPushButton* screenshot_button;
MainWidget(QWidget* parent=nullptr) : QOpenGLWidget(parent){
screenshot_button = new QPushButton("sreenshot", this);
QObject::connect(screenshot_button, &QPushButton::clicked, [this](){
take_screenshot();
});
}
void initializeGL(){
initializeOpenGLFunctions();
}
void take_screenshot(){
QPixmap pixmap(size());
render(&pixmap, QPoint(), QRegion(rect()));
pixmap.save("screenshot.png");
}
void paintGL(){
QPainter painter(this);
painter.beginNativePainting();
glClearColor(0.80, 0.80, 0.80, 1);
glClear(GL_COLOR_BUFFER_BIT);
painter.endNativePainting();
// this disappears when the screenshot button is pressed!
// also it is not present in the screenshot
painter.drawRect(QRect(0, 0, 100, 100));
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWidget w;
w.show();
return a.exec();
}
Before pressing the button the widget looks normal:
But after pressing the screenshot button, the rectangle disappears from the widget (also it is absent from screenshot.png
) until I resize the window which forces a re-render.
I am using qt 6.5
on windows 10.
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.
Meaning it grabs from the framebuffer unlike QWidget::grab
and QWidget::render
which ask the widget to render itself.
So it could be used instead of render()
to avoid the problems caused by combining the latter with OpenGL:
void take_screenshot()
{
QGuiApplication::primaryScreen()->grabWindow(winId()).save("screenScreenshot.png");
}
Less straightforward but just in case render
is a must.
Use a bool
to disable openGL when calling render
in take_screenshot()
, and make sure you call grabFramebuffer()
before.
void take_screenshot()
{
grabFramebuffer();
QPixmap pixmap(size());
enable_opengl=false;
render(&pixmap, QPoint(), QRegion(rect()));
enable_opengl=true;
pixmap.save("renderScreenshot.png");
}
void paintGL()
{
QPainter painter(this);
if(enable_opengl)
{
glClearColor(0.80, 0.80, 0.80, 1);
glClear(GL_COLOR_BUFFER_BIT);
}
painter.fillRect(QRect(10, 10, 100, 100), Qt::green);
}