QOpenGLWidget简介
QOpenGLWidget类是用于渲染OpenGL图形的部件。QOpenGLWidget提供了用于显示集成到Qt应用程序中的OpenGL图形的功能。使用非常简单:让应用的类继承自它,并像使用其他任何QWidget一样使用子类,而且它可以在使用QPainter和标准OpenGL渲染命令之间进行选择。
QOpenGLWidget提供了三个函数,在子类中重新实现它们就可以执行一个典型的OpenGL任务:
- paintGL() 渲染OpenGL场景。在部件需要更新时就会调用它。
- resizeGL() 设置OpenGL视口,投影等。只要调整了窗口部件的大小(以及新创建的窗口部件自动获得resize事件而首次显示时),就会被调用。
- initializeGL() 设置OpenGL资源和状态。在第一次调用resizeGL()或paintGL()之前它被调用一次。
QOpenGLWidget的子类可以通过以下方式渲染纯3D内容:
- 重新实现initializeGL()和resizeGL()函数以设置OpenGL状态并提供透视图转换。
- 重新实现paintGL()来绘制3D场景,它仅调用OpenGL函数。
仅使用QPainter执行绘图时,还可以像执行普通部件一样执行绘图:
- 重新实现paintEven()t函数。
- 构造一个以部件为目标的QPainter对象。将小部件传递给构造函数或QPainter.begin()函数。
- 使用QPainter的成员函数绘制基本图元。
- 绘制完成后,然后销毁QPainter实例。或者显式调用QPainter.end()。
QOpenGLWidget常用方法:
- context(): 返回控件所使用的QOpenGLContext, 如果未初始化,则返回None。
- defaultFramebufferObject():返回帧缓冲区句柄,如果未初始化,则返回None。
- doneCurrent(): 释放Context。
- format(): 返回本控件及其顶层窗口使用的Context和Surface格式。
- grabFramebuffer(): 渲染并返回帧缓冲区的32位RGB图像。
- makeCurrent(): 通过使相应的context成为当前context并在其上绑定framebuffer对象,为渲染此控件的OpenGL内容做准备。
- setFormat(): 设置所需的表面(Surface)格式。
- setTextureFormat(): 设置自定义内部纹理格式。
- textureFormat(): 返回内部纹理格式。
QOpenGLWidget常用信号:
- aboutToCompose(): 当控件的顶级窗口开始合成其QOpenGLWidget子级和其他控件的纹理时,将发出此信号。
- aboutToResize(): 当窗口部件的大小发生更改时,将发出此信号,因此将重新创建帧缓冲区对象。
- frameSwapped(): 在窗口部件的顶级窗口完成合成后发出此信号。
- resized(): 调整窗口部件的大小而重新创建了帧缓冲对象之后立即发出此信号。
QOpenGLWidget类继承关系:

范例代码
最简单的QOpenGLWidget子类可能如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class MyGLWidget(QOpenGLWidget): def __init(self, parent=None): super(MyGLWidget, self).__init__(parent) def initializeGL(self): # 设置渲染context,加载shader和资源等 version_profile = QOpenGLVersionProfile() version_profile.setVersion(2,0) self.gl = self.context().versionFunctions(version_profile) self.gl.initializeOpenGLFunctions() ... def resizeGL(self, w, h): # 更新投射矩阵和其他尺寸相关的设置 self.projection.setToIdentity() self.projection.perspective(45, w / h, 0.01, 100) ... def paintGL(): #绘制场景 self.gl.glClear(self.gl.GL_COLOR_BUFFER_BIT) |
在演示代码中,使用OpenGL渲染了一个三个顶点带不同颜色的三角形,完整代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | import sys from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtCore import Qt from PyQt5.QtGui import QColor, QOpenGLVersionProfile from PyQt5.QtWidgets import (QApplication, QWidget, QOpenGLWidget, QHBoxLayout) class MyGLWidget(QOpenGLWidget): def __init__(self, parent=None): super(MyGLWidget, self).__init__(parent) def initializeGL(self): version_profile = QOpenGLVersionProfile() version_profile.setVersion(2, 0) self.gl = self.context().versionFunctions(version_profile) self.gl.initializeOpenGLFunctions() #设置背景色 self.gl.glClearColor(0.2, 0.4, 0.52, 1.0) #深度测试 self.gl.glEnable(self.gl.GL_DEPTH_TEST) def paintGL(self): self.gl.glClear(self.gl.GL_COLOR_BUFFER_BIT | self.gl.GL_DEPTH_BUFFER_BIT) self.gl.glLoadIdentity() #self.gl.glRotated(30.0, 1.0, 0.0, 0.0) self.gl.glBegin(self.gl.GL_TRIANGLES) self.gl.glColor3d(1.0, 0.0, 0.0) self.gl.glVertex3d(0.0, 1.0, 0.0) self.gl.glColor3d(0.0, 1.0, 0.0) self.gl.glVertex3d(-1.0, -1.0, 0.0) self.gl.glColor3d(0.0, 0.0, 1.0) self.gl.glVertex3d(1.0, -1.0, 0.0) self.gl.glEnd() def resizeGL(self, width, height): side = min(width, height) if side < 0: return #视口 self.gl.glViewport((width - side) // 2, (height - side) // 2, side, side) self.gl.glMatrixMode(self.gl.GL_PROJECTION) self.gl.glLoadIdentity() #正交投射 self.gl.glOrtho(-1.5, 1.5, -1.5, 1.5, -10, 10) self.gl.glMatrixMode(self.gl.GL_MODELVIEW) class DemoOpenGLWidget(QWidget): def __init__(self, parent=None): super(DemoOpenGLWidget, self).__init__(parent) # 设置窗口标题 self.setWindowTitle('实战PyQt5: QOpenGLWidget Demo!') # 设置窗口大小 self.resize(400, 320) self.initUi() def initUi(self): glWidget = MyGLWidget() mainLayout = QHBoxLayout() mainLayout.addWidget(glWidget) self.setLayout(mainLayout) if __name__ == '__main__': app = QApplication(sys.argv) window = DemoOpenGLWidget() window.show() sys.exit(app.exec()) |
运行结果如下图:

测试QOpenGLWidget
本文知识点
- 如何实现一个OpenGL渲染任务;
- OpenGL的状态机制;
- OpenGL 渲染一个三角形。
前一篇: 实战PyQt5: 087-视图类QGraphicsView