QOpenGLWidget渲染至QPixmap时QPainter绘制内容消失问题求助
QOpenGLWidget混合渲染截图丢失QPainter内容问题解决
问题现象
使用QOpenGLWidget同时进行OpenGL原生渲染和QPainter绘制时,界面显示正常,但调用render()生成截图后:
- QPainter绘制的内容从界面上消失,直到窗口调整大小触发重绘才恢复
- 生成的截图中也没有QPainter绘制的元素
复现代码如下:
#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(); // 点击截图按钮后该矩形消失!截图中也不存在 painter.drawRect(QRect(0, 0, 100, 100)); } }; int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWidget w; w.show(); return a.exec(); }
问题原因
render()方法会触发一次额外的paintGL()调用,但此次调用时OpenGL上下文状态与正常绘制不一致,导致QPainter的绘制状态被破坏- 直接在
paintGL()中初始化QPainter(this)并混合beginNativePainting()/endNativePainting(),会干扰QPainter与OpenGL上下文的交互逻辑,后续绘制无法正确执行
解决方案
方案1:使用grab()替代render()(推荐)
grab()方法专门用于捕获部件的可视化内容,更适配QOpenGLWidget的混合渲染场景,同时手动触发重绘恢复界面状态:
修改后的代码:
#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("screenshot", this); QObject::connect(screenshot_button, &QPushButton::clicked, [this](){ take_screenshot(); }); } void initializeGL(){ initializeOpenGLFunctions(); } void take_screenshot(){ // 使用grab()直接捕获部件完整内容 QPixmap pixmap = grab(); pixmap.save("screenshot.png"); // 手动触发重绘,确保界面元素正常显示 update(); } void paintGL(){ // 先执行OpenGL原生渲染,无需QPainter包裹 glClearColor(0.80, 0.80, 0.80, 1); glClear(GL_COLOR_BUFFER_BIT); // 初始化QPainter进行2D绘制,自动处理上下文切换 QPainter painter(this); painter.drawRect(QRect(0, 0, 100, 100)); } }; int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWidget w; w.show(); return a.exec(); }
方案2:严格管理OpenGL上下文与QPainter状态(若需保留render())
如果必须使用render(),需在截图前后保存/恢复OpenGL上下文状态,并确保QPainter正确初始化与结束:
void take_screenshot(){ QPixmap pixmap(size()); // 保存当前OpenGL上下文状态 makeCurrent(); QOpenGLContext* ctx = context(); ctx->saveState(); render(&pixmap, QPoint(), QRegion(rect())); pixmap.save("screenshot.png"); // 恢复上下文状态并触发重绘 ctx->restoreState(); doneCurrent(); update(); } void paintGL(){ QPainter painter; // 显式begin/end管理QPainter生命周期 painter.begin(this); painter.beginNativePainting(); glClearColor(0.80, 0.80, 0.80, 1); glClear(GL_COLOR_BUFFER_BIT); painter.endNativePainting(); painter.drawRect(QRect(0, 0, 100, 100)); painter.end(); }
效果验证
修改后:
- 截图可完整捕获OpenGL渲染内容与QPainter绘制元素
- 点击截图按钮后,界面上的QPainter内容不会消失,无需手动调整窗口触发重绘
内容的提问来源于stack exchange,提问作者ali mostafavi
相关产品推荐
相关产品推荐

