本页内容

QOpenGLWindow Class

QOpenGLWindow 类是QWindow 的一个便捷子类,用于执行 OpenGL 绘制。更多内容...

头文件: #include <QOpenGLWindow>
CMake: find_package(Qt6 REQUIRED COMPONENTS OpenGL)
target_link_libraries(mytarget PRIVATE Qt6::OpenGL)
qmake: QT += opengl
继承自: QPaintDeviceWindow

公共类型

enum UpdateBehavior { NoPartialUpdate, PartialUpdateBlit, PartialUpdateBlend }

公共函数

QOpenGLWindow(QOpenGLWindow::UpdateBehavior updateBehavior = NoPartialUpdate, QWindow *parent = nullptr)
QOpenGLWindow(QOpenGLContext *shareContext, QOpenGLWindow::UpdateBehavior updateBehavior = NoPartialUpdate, QWindow *parent = nullptr)
virtual ~QOpenGLWindow()
QOpenGLContext *context() const
GLuint defaultFramebufferObject() const
void doneCurrent()
QImage grabFramebuffer()
bool isValid() const
void makeCurrent()
QOpenGLContext *shareContext() const
QOpenGLWindow::UpdateBehavior updateBehavior() const

信号

void frameSwapped()

受保护函数

virtual void initializeGL()
virtual void paintGL()
virtual void paintOverGL()
virtual void paintUnderGL()
virtual void resizeGL(int w, int h)

重新实现的受保护函数

virtual void paintEvent(QPaintEvent *event) override
virtual void resizeEvent(QResizeEvent *event) override

详细说明

QOpenGLWindow 是一个增强版的QWindow ,它允许使用与QOpenGLWidget 兼容的API轻松创建执行OpenGL渲染的窗口。与QOpenGLWidget 不同,QOpenGLWindow 不依赖于小部件模块,并提供更好的性能。

典型的应用程序会继承 QOpenGLWindow 并重写以下虚函数:

  • initializeGL() 用于执行 OpenGL 资源初始化
  • resizeGL() 用于设置变换矩阵及其他与窗口大小相关的资源
  • paintGL() 用于发出 OpenGL 命令或使用QPainter

要安排重绘,请调用update()函数。请注意,这不会立即导致调用paintGL()。连续多次调用update()并不会以任何方式改变该行为。

这是一个插槽,因此可以连接到QChronoTimer::timeout()信号以执行动画。但请注意,在现代OpenGL环境中,依赖显示器的垂直刷新率进行同步是一个更好的选择。有关交换间隔的描述,请参阅setSwapInterval()。 当交换间隔为1 (这是大多数系统默认的情况)时,QOpenGLWindow在每次重绘后内部执行的swapBuffers()调用将阻塞并等待垂直同步(vsync)。这意味着,每当交换完成后,都可以通过调用update()再次安排更新,而无需依赖定时器。

若要为上下文请求特定配置,请像处理其他QWindow 一样使用setFormat()。这允许(除其他功能外)请求指定的OpenGL版本和配置文件,或启用深度缓冲区和模板缓冲区。

注意:应用程序需自行 确保从底层窗口系统接口请求深度缓冲区和模板缓冲区。若未请求非零大小的深度缓冲区,则无法保证深度缓冲区可用,从而导致与深度测试相关的 OpenGL 操作可能无法按预期运行。

常用的深度缓冲区和模板缓冲区大小请求值分别为 24 和 8。例如,一个 QOpenGLWindow 的子类可以在其构造函数中这样做:

QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
setFormat(format);

与QWindow 不同,QOpenGLWindow允许在其自身上打开绘图器,并执行基于QPainter 的绘制操作。

QOpenGLWindow 支持多种更新行为。默认的NoPartialUpdate 等同于基于常规 OpenGL 的QWindow 。相比之下,PartialUpdateBlit 和PartialUpdateBlend 更符合QOpenGLWidget 的工作方式,即始终存在一个额外的专用帧缓冲区对象。 这些模式通过牺牲部分性能,允许在每次绘制时仅重绘较小区域,并将其余内容保留自上一帧。这对使用QPainter 进行增量渲染的应用程序非常有用,因为这样它们就不必在每次调用paintGL() 时重绘整个窗口内容。

与QOpenGLWidget 类似,QOpenGLWindow支持Qt::AA_ShareOpenGLContexts 属性。启用该属性后,所有QOpenGLWindow实例的OpenGL上下文将相互共享。这使得各实例能够访问彼此可共享的OpenGL资源。

有关 Qt 中图形处理的更多信息,请参阅“图形”。

成员类型文档

enum QOpenGLWindow::UpdateBehavior

此枚举描述了QOpenGLWindow 的更新策略。

常量值描述
QOpenGLWindow::NoPartialUpdate0表示每次更新时都会重绘整个窗口表面,因此无需额外的帧缓冲区。这是大多数情况下使用的设置,其效果等同于直接通过QWindow 进行绘制。
QOpenGLWindow::PartialUpdateBlit1表示在 `paintGL()` 中执行的绘制操作不会覆盖整个窗口。在这种情况下,系统会在后台创建一个额外的帧缓冲区对象,而 `paintGL()` 中执行的渲染将针对该帧缓冲区。随后,在每次绘制后,该帧缓冲区会被复制到窗口表面的默认帧缓冲区上。 这使得可以在paintGL() 中使用基于QPainter 的绘制代码,该代码每次仅重绘较小区域,因为与 NoPartialUpdate 不同,先前内容会被保留。
QOpenGLWindow::PartialUpdateBlend2与 PartialUpdateBlit 类似,但它不使用帧缓冲区复制,而是通过绘制一个启用了混合功能的带纹理四边形来呈现额外帧缓冲区的内容。这与 PartialUpdateBlit 不同,它允许使用 alpha 混合内容,并且即使 glBlitFramebuffer 不可用时也能正常工作。 就性能而言,此设置可能比 PartialUpdateBlit 稍慢一些。

成员函数文档

[explicit] QOpenGLWindow::QOpenGLWindow(QOpenGLWindow::UpdateBehavior updateBehavior = NoPartialUpdate, QWindow *parent = nullptr)

使用给定的parent 和updateBehavior 创建一个新的QOpenGLWindow。

另请参阅 QOpenGLWindow::UpdateBehavior 。

[explicit] QOpenGLWindow::QOpenGLWindow(QOpenGLContext *shareContext, QOpenGLWindow::UpdateBehavior updateBehavior = NoPartialUpdate, QWindow *parent = nullptr)

使用给定的parent 和updateBehavior 创建一个新的QOpenGLWindow。该QOpenGLWindow的上下文将与shareContext 共享。

另请参阅 QOpenGLWindow::UpdateBehavior 和shareContext 。

[virtual noexcept] QOpenGLWindow::~QOpenGLWindow()

销毁QOpenGLWindow 实例,并释放其资源。

在析构函数中,将 OpenGLWindow 的上下文设为当前上下文,从而能够安全地销毁任何可能需要释放属于该窗口提供的上下文的 OpenGL 资源的子对象。

警告:如果 将封装 OpenGL 资源(如QOpenGLBuffer 、QOpenGLShaderProgram 等)的对象作为QOpenGLWindow 子类的成员,则可能还需要在该子类的析构函数中添加对makeCurrent() 的调用。 由于 C++ 对象销毁的规则,这些对象将在调用此函数之前被销毁(但此时子类的析构函数已执行完毕),因此在此函数中将 OpenGL 上下文设为当前上下文的操作发生得太晚,无法确保这些对象的安全释放。

另请参阅 makeCurrent 。

QOpenGLContext *QOpenGLWindow::context() const

返回该窗口使用的QOpenGLContext 对象;若尚未初始化,则返回0 。

GLuint QOpenGLWindow::defaultFramebufferObject() const

该窗口使用的帧缓冲区对象句柄。

当更新行为设置为NoPartialUpdate 时,不存在单独的帧缓冲区对象。在这种情况下,返回值是默认帧缓冲区的ID。

否则,返回帧缓冲区对象的 ID 值;若尚未初始化,则返回0 。

void QOpenGLWindow::doneCurrent()

释放上下文。

在大多数情况下无需调用此函数,因为当调用 `paintGL()` 时,控件会确保上下文被正确绑定和释放。

另请参阅 makeCurrent()。

[signal] void QOpenGLWindow::frameSwapped()

该信号是在可能导致阻塞的buffer swap 执行完毕后发出的。希望与垂直刷新同步进行持续重绘的应用程序,应在接收到此信号时调用update()。与传统使用定时器的方式相比,这能带来更流畅的使用体验。

QImage QOpenGLWindow::grabFramebuffer()

返回帧缓冲区的副本。

注意:这是一项 可能消耗较多的操作,因为它依赖于 glReadPixels() 来读取像素。此过程可能较慢,并可能导致 GPU 管道停滞。

注意:当 与更新行为NoPartialUpdate 结合使用时 ,如果 在前缓冲区和后缓冲区交换之后调用此函数,返回的图像可能不包含预期内容(除非在底层窗口系统接口中启用了“保留交换”功能)。 在此模式下,该函数从后缓冲区读取数据,而其内容可能与屏幕(前缓冲区)上的内容不一致。在这种情况下,唯一可以安全使用此函数的位置是paintGL()或paintOverGL()。

[virtual protected] void QOpenGLWindow::initializeGL()

在首次调用paintGL()或resizeGL()之前,会调用一次此虚拟函数。请在子类中重写该函数。

该函数应初始化所有必要的 OpenGL 资源和状态。

无需调用 `makeCurrent()`,因为在调用本函数时该操作已执行完毕。但请注意,若使用部分更新模式,此时帧缓冲区尚不可用,因此请避免在此处发出绘制调用。应将此类调用推迟至 `paintGL()` 中执行。

另请参阅 paintGL() 和resizeGL()。

bool QOpenGLWindow::isValid() const

如果窗口的 OpenGL 资源(如上下文)已成功初始化,则返回true 。请注意,在窗口被显示出来之前,返回值始终为false 。

void QOpenGLWindow::makeCurrent()

通过将相应的上下文设为当前上下文,并在该上下文中绑定帧缓冲区对象(如有),为本窗口的 OpenGL 内容渲染做好准备。

在大多数情况下无需调用此函数,因为在调用 `paintGL()` 之前它会自动被调用。不过,该函数仍被提供,以支持高级的多线程场景——在这些场景中,除 GUI 或主线程之外的其他线程可能需要更新表面或帧缓冲区的内容。有关线程相关问题的更多信息,请参阅QOpenGLContext 。

当底层平台窗口已被销毁时,此函数同样适用。这意味着从QOpenGLWindow 子类的析构函数中调用此函数是安全的。如果不存在本机窗口,则会改用离屏表面。这确保了只要先调用此函数,析构函数中的 OpenGL 资源清理操作总能正常进行。

另请参阅 QOpenGLContext 、context()、paintGL() 以及doneCurrent()。

[override virtual protected] void QOpenGLWindow::paintEvent(QPaintEvent *event)

重写:QPaintDeviceWindow::paintEvent(QPaintEvent *event)。

绘制event 处理程序。调用paintGL()。

另请参阅 paintGL()。

[virtual protected] void QOpenGLWindow::paintGL()

每当需要绘制窗口内容时,都会调用此虚拟函数。请在子类中重写该函数。

无需调用makeCurrent(),因为在调用此函数时,该操作已经完成。

在调用此函数之前,上下文和帧缓冲区(如果存在)已被绑定,并且通过调用 glViewport() 设置了视口。框架不会设置其他状态,也不会执行清屏或绘制操作。

注意:当 使用部分更新行为(如 `PartialUpdateBlend`)时, 前一次 `paintGL()` 调用的输出将被保留;在本次函数调用中完成额外绘制后,该内容将通过位图复制或混合的方式叠加在 `paintUnderGL()` 直接绘制到窗口上的内容之上。

另请参阅 initializeGL()、resizeGL()、paintUnderGL()、paintOverGL() 以及UpdateBehavior 。

[virtual protected] void QOpenGLWindow::paintOverGL()

每次调用paintGL()后,都会调用此虚拟函数。

当更新模式设置为NoPartialUpdate 时,该函数与paintGL()之间没有区别,在两者中进行渲染都会得到相同的结果。

与paintUnderGL() 一样,无论更新行为如何,此函数中的渲染都针对窗口的默认帧缓冲区。它在paintGL() 返回且完成位图复制(PartialUpdateBlit )或四边形绘制(PartialUpdateBlend )之后被调用。

另请参阅 paintGL()、paintUnderGL() 以及UpdateBehavior 。

[virtual protected] void QOpenGLWindow::paintUnderGL()

每次调用paintGL()之前,都会先调用该虚拟函数。

当更新模式设置为NoPartialUpdate 时,该函数与paintGL()之间没有区别,在两者中进行渲染都会得到相同的结果。

当使用PartialUpdateBlend 时,差异就变得显著,因为此时会使用一个额外的帧缓冲区对象。在这种情况下,paintGL() 针对的是这个额外的帧缓冲区对象,该对象会保留其内容;而 paintUnderGL() 和paintOverGL() 则针对默认帧缓冲区,即直接针对窗口表面,其内容在每个帧显示后都会丢失。

注意: 当更新行为为PartialUpdateBlit 时,请避免 依赖此函数。该模式会在每次调用paintGL()后,将paintGL()所使用的额外帧缓冲区内容复制到默认帧缓冲区上,从而覆盖此函数中生成的所有绘制内容。

另请参阅 paintGL()、paintOverGL() 和UpdateBehavior 。

[override virtual protected] void QOpenGLWindow::resizeEvent(QResizeEvent *event)

重写:QWindow::resizeEvent(QResizeEvent *ev)。

event 的大小调整处理程序。调用resizeGL()。

另请参阅 resizeGL()。

[virtual protected] void QOpenGLWindow::resizeGL(int w, int h)

每当小部件被调整大小时,都会调用此虚拟函数。请在子类中重新实现该函数。新尺寸将通过w 和h 传递进来。

注意:这 仅仅是一个便利函数,旨在提供与QOpenGLWidget 兼容的 API。与QOpenGLWidget 不同,派生类可以自由选择重写resizeEvent() 而不是此函数。

注意:请避免 在此函数中发出 OpenGL 命令,因为调用时可能没有活动上下文。如果无法避免,请调用makeCurrent()。

注意: 无需在此处安排 更新。窗口系统会发送暴露事件,这些事件会自动触发更新。

另请参阅 initializeGL() 和paintGL()。

QOpenGLContext *QOpenGLWindow::shareContext() const

返回请求与该窗口的QOpenGLContext 共享的QOpenGLContext 。

QOpenGLWindow::UpdateBehavior QOpenGLWindow::updateBehavior() const

返回此QOpenGLWindow 的更新行为。

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.