When to use paintEvent and paintGL in Qt?

后端 未结 1 1185
醉酒成梦
醉酒成梦 2021-01-27 04:33

I am using QOpenGLWidget and can\'t understand where should I put drawing code: inside overriden paintGL or inside overriden paintEvent.

Should I call base class versio

1条回答
  •  挽巷
    挽巷 (楼主)
    2021-01-27 04:50

    The short answer: Open GL drawing in QOpenGLWidget should happen in QOpenGLWidget::paintGL().

    When OpenGL commands shall be called, a pre-condition is that the resp. OpenGL context has been activated before. This is what QOpenGLWidget::paintGL() ensures:

    There is no need to call makeCurrent() because this has already been done when this function is called.

    Before invoking this function, the context and the framebuffer are bound, and the viewport is set up by a call to glViewport().

    Btw. another pre-condition is that the resp. OpenGL context has been created at all.


    To find out more about this I digged a bit deeper – in QOpenGLWidget::paintEvent() (on woboq.org):

    void QOpenGLWidget::paintEvent(QPaintEvent *e)
    {
        Q_UNUSED(e);
        Q_D(QOpenGLWidget);
        if (!d->initialized)
            return;
        if (updatesEnabled())
            d->render();
    }
    
    1. The paint event does nothing as long as initialization is not yet done. (I didn't dig deeper but I'm sure that initialization involves calling of QOpenGLWidget::initializeGL().)

    2. The paint event requests rendering.

    Following the code by eyes (stricly speaking: mouse clicks), d->render() calls QOpenGLWidgetPrivate::render() which in turn calls finally QOpenGLWidgetPrivate::invokeUserPaint() and here we are:

    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;
    }
    

    (The comments are mine.)

    So, if QOpenGLWidget::paintEvent() is overloaded then it should call the paintEvent() of base class. (Otherwise, the OpenGL rendering will certainly break.)


    Finally, how to force rerender of graphics when I change geometry? What method should I call?

    This is actually answered in the description on QOpenGLWidget:

    If you need to trigger a repaint from places other than paintGL() (a typical example is when using timers to animate scenes), you should call the widget's update() function to schedule an update.


    In case, I misunderstood the intention of OP, and the actual question was where to put QPainter drawing in QOpenGLWidget – I once wrote an answer to SO: Paint a rect on qglwidget at specifit times regarding mixing OpenGL commands and QPainter drawing in paintGL().

    0 讨论(0)
提交回复
热议问题