何时在Qt中使用paintEvent和paintGL?

When to use paintEvent and paintGL in Qt?

本文关键字:paintEvent paintGL Qt 何时      更新时间:2023-10-16

我正在使用QOpenGLWidget,但无法理解我应该在哪里放置绘图代码:在覆盖的paintGL内部或在覆盖的paintEvent内部。

我应该调用这些函数的基类版本吗?

这些功能是如何连接的? paintGL推出paintEvent,反之亦然?也许它们由于非交叉原因(即恢复窗口、绘制一些 3D 几何形状、更改窗口大小(而启动?那么这些原因是什么呢?

最后,当我更改几何图形时,如何强制重新渲染图形?我应该调用什么方法?

简短的回答:在QOpenGLWidget中打开GL绘图应该发生在QOpenGLWidget::paintGL()中。

当调用 OpenGL 命令时,一个先决条件是之前已经激活了 OpenGL 上下文。这就是QOpenGLWidget::paintGL()确保:

无需调用makeCurrent()因为调用此函数时已经执行此操作。

在调用此函数之前,上下文和帧缓冲区是绑定的,视口是通过调用 glViewport(( 来设置的。

顺便说一句,另一个先决条件是已经创建了OpenGL上下文。


为了了解更多信息,我更深入地挖掘了 - 在QOpenGLWidget::paintEvent()(woboq.org(:

void QOpenGLWidget::paintEvent(QPaintEvent *e)
{
Q_UNUSED(e);
Q_D(QOpenGLWidget);
if (!d->initialized)
return;
if (updatesEnabled())
d->render();
}
  1. 只要尚未完成初始化,paint 事件就不执行任何操作。(我没有深入挖掘,但我确信初始化涉及调用QOpenGLWidget::initializeGL()

  2. 绘制事件请求呈现。

通过眼睛跟踪代码(严格地说:鼠标点击(,d->render()调用QOpenGLWidgetPrivate::render()而调用最终QOpenGLWidgetPrivate::invokeUserPaint(),我们在这里:

void QOpenGLWidgetPrivate::invokeUserPaint()
{
Q_Q(QOpenGLWidget);
QOpenGLContext *ctx = QOpenGLContext::currentContext();
Q_ASSERT(ctx && fbo);
QOpenGLFunctions *f = ctx->functions();
QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = fbo->handle();
f->glViewport(0, 0, q->width() * q->devicePixelRatioF(), q->height() * q->devicePixelRatioF());
inPaintGL = true;
// vvvvvvvvvvvv
q->paintGL();
// ^^^^^^^^^^^^
inPaintGL = false;
flushPending = true;
QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = 0;
}

(评论是我的。

因此,如果QOpenGLWidget::paintEvent()重载,那么它应该调用基类的paintEvent()。 (否则,OpenGL 渲染肯定会中断。


最后,当我更改几何图形时,如何强制重新渲染图形?我应该调用什么方法?

这实际上在QOpenGLWidget的描述中得到了回答:

如果需要从 paintGL(( 以外的地方触发重绘(一个典型的示例是使用计时器对场景进行动画处理时(,则应调用小部件的update()函数来计划更新。


万一,我误解了OP的意图,实际的问题是QPainter绘图放在QOpenGLWidget的位置 - 我曾经写过一个答案 SO:在关于混合OpenGL命令和QPainter绘图的特定时间在qglwidget上绘制一个矩形paintGL()