Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
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 versions of these functions?
How these functions are connected? paintGL launches paintEvent or vice-versa? Maybe they launch as a result of non intersecting reasons (i.e. restore window, draw some 3D geometry, change window size)? What are these reasons then?
Finally, how to force rerender of graphics when I change geometry? What method should I call?
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.
–
–
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.