【问题标题】:When to use paintEvent and paintGL in Qt?Qt 中何时使用paintEvent 和paintGL?
【发布时间】:2018-06-14 10:25:39
【问题描述】:

我正在使用QOpenGLWidget,但不明白我应该将绘图代码放在哪里:在覆盖的paintGL 内或在覆盖的paintEvent 内。

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

这些功能是如何联系起来的? paintGL 启动paintEvent 或反之亦然?也许它们是由于不相交的原因而启动的(即恢复窗口、绘制一些 3D 几何图形、更改窗口大小)?那么这些原因是什么呢?

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

【问题讨论】:

    标签: c++ qt


    【解决方案1】:

    简短的回答:QOpenGLWidget 中的 Open 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;
    }
    

    (这些cmets是我的。)

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


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

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

    如果您需要从paintGL() 以外的地方触发重绘(典型示例是使用计时器为场景设置动画时),您应该调用小部件的update() 函数来安排更新。


    以防万一,我误解了OP的意图,实际的问题是在QOpenGLWidget中放置QPainter绘图 - 我曾经写过一个关于混合OpenGL命令和QPainter绘图在@中的SO: Paint a rect on qglwidget at specifit times的答案987654344@.

    【讨论】:

    • 很好的答案!现在很清楚,当我想重绘几何图形时,我可以简单地调用 update(),它会调用 paintEvent(),最后会调用 paintGL()。
    • 是的,没错。我正要添加这部分。这也意味着窗口大小调整、重叠等也应该强制更新(像往常一样)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多