QOpenGLWidget加入QGraphicsScene后paintGL未调用及异常问题求助
我来帮你分析并解决这个问题——当把MyGLWidget通过QGraphicsProxyWidget添加到QGraphicsScene后,paintGL没被触发,这本质是QGraphicsView的渲染机制和直接显示QOpenGLWidget的差异导致的,下面是具体的解决方案:
核心原因
默认情况下,QGraphicsView使用普通的QWidget作为viewport(软件渲染),这时候被代理的QOpenGLWidget无法正确激活OpenGL上下文,自然不会调用paintGL。同时,场景中的widget更新机制和独立显示时也有区别,需要手动调整触发逻辑。
分步解决方案
1. 让QGraphicsView使用OpenGL渲染
修改你的main.cpp,给QGraphicsView设置一个QOpenGLWidget作为viewport,这样整个场景会在OpenGL上下文中渲染,代理的MyGLWidget才能正常触发paintGL:
int main(int argc, char *argv[]) { QApplication a(argc, argv); QSurfaceFormat format; format.setDepthBufferSize(24); format.setStencilBufferSize(8); format.setVersion(3, 2); format.setProfile(QSurfaceFormat::CoreProfile); format.setSamples(4); QSurfaceFormat::setDefaultFormat(format); MyGLWidget w; w.setFormat(format); QGraphicsScene scene; QGraphicsProxyWidget* proxy = scene.addWidget(&w); scene.addText("Hello"); QGraphicsView view(&scene); // 关键:设置OpenGL viewport,确保场景用OpenGL渲染 view.setViewport(new QOpenGLWidget); // 可选:开启高质量渲染提示,提升效果 view.setRenderHint(QPainter::HighQualityAntialiasing); view.show(); // 手动触发一次更新,确保首次paintGL被调用 w.update(); return a.exec(); }
2. 设置自动更新渲染
如果需要持续自动触发paintGL(比如做动画),可以在MyGLWidget的构造函数中添加定时器,定期调用update()方法:
// MyGLWidget.cpp MyGLWidget::MyGLWidget(QWidget* parent) : QOpenGLWidget(parent) { // 创建定时器,每16ms触发一次更新(约60FPS) QTimer* updateTimer = new QTimer(this); connect(updateTimer, &QTimer::timeout, this, &MyGLWidget::update); updateTimer->start(16); }
这样paintGL就会被周期性调用,实现自动渲染。如果不需要持续动画,也可以在需要更新的时机手动调用w.update()来触发一次渲染。
3. 解决异常问题
你遇到的奇怪异常,大概率是因为OpenGL上下文冲突导致的。通过上面两步:先设置全局默认的QSurfaceFormat,再给QGraphicsView设置OpenGL viewport,确保整个应用的OpenGL上下文一致,就能避免这类异常。另外注意不要在paintGL中混合OpenGL原始调用和QPainter后未正确管理状态——你的当前代码中先调用glClear再使用QPainter是没问题的,QPainter会自动处理上下文状态切换。
验证效果
修改后运行代码,你会看到MyGLWidget的紫色背景、居中的"Testing"文本和椭圆都能正常显示,而且定时器会自动触发paintGL更新。
内容的提问来源于stack exchange,提问作者Syaiful Nizam Yahya

