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
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();
}
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()
.)
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()
.