views:

2204

answers:

5

I've derived from QGLWidget before, like so:

class MyGLWidget : public QGLWidget
{
public:
   // stuff...

   virtual void initializeGL() { /* my custom OpenGL initialization routine */ }

   // more stuff...
};

However, I find that if I try to initialize a QGraphicsView with my custom QGLWidget as the viewport, initializeGL doesn't get called (setting a breakpoint within the Qt library, neither does QGLWidget::initializeGL() when created plain).

// initializeGL, resizeGL, paintGL not called
ui.graphicsView->setViewport(new MyGLWidget(QGLFormat(QGL::DoubleBuffer)));

// initializeGL, resizeGL, paintGL *still* not called
ui.graphicsView->setViewport(new QGLWidget(QGLFormat(QGL::DoubleBuffer)));

Where is the correct location to place the code that currently resides in MyGLWidget::initializeGL()?

A: 

initializeGL() won't get called until the first call to either paintGL() or resizeGL() and not when the widget is constructed. This may happen as late as when the widget is first made visible.

Troubadour
Here's the problem though: paintGL and resizeGL aren't being called either, since MyGLWidget is being used as the viewport, not as a widget added to the layout. I should have been more specific in my question; I'll update it.
mos
A: 

The pain, the pain, ... integrating widgets derived from QGlWidgets into QGraphicsView is no fun, of the parts of Qt that I know this is definitely one of the messier areas. I ended up using a part of kgllib (out of kde) called widgetproxy that is a very decent wrapper around a QGlWidget. I modified it to fit my needs but works reasonably well for most general cases where you want to use an exisiting class derived from QGlWidget inside a QGraphicsView and draw other things on top of it.

Harald Scheirich
A: 

I'm going to go ahead and answer my own question. This isn't optimal, but this is how I've gotten around the problem.

Instead of

ui.graphicsView->setViewport(new MyGLWidget(QGLFormat(QGL::DoubleBuffer)));

I've got this instead:

ui.graphicsView->setViewport(new QGLWidget(new CustomContext(QGLFormat(QGL::SampleBuffers))));

CustomContext is a class that derives from QGLContext. I've overridden the create member, like so:

virtual bool create(const QGLContext *shareContext = 0)
{
    if(QGLContext::create(shareContext))
    {
        makeCurrent();

        /* do my initialization here */

        doneCurrent();

        return true;
    }

    return false;
}

I don't think this is the optimal way to do this, but it's better than the alternative of not having a specific initialization step at all. I'd still be happy to have someone leave a better answer!

mos
A: 

So what I've found is QGraphicsView installs a custom eventFilter on your QGLWidget viewport so it never sees the initialize/resize/repaint events. This probably was done to make it work properly with drawBackground() etc.

My current best resolution is to catch the desired event either in QGraphicsView::resizeEvent()/etc, or install a custom eventFilter on your QGLWidget derived class to catch the resize/paint/etc events before QGraphicsView's custom eventFilter swallows them.

NuShrike
+1  A: 

The setupViewport slot of a custom QGraphicsView could be used to call updateGL() on the QGLWidget, which will cause initializeGL() to be called.

class MyGraphicsView : public QGraphicsView
{
    //... The usual stuff

protected slots:
    virtual void setupViewport(QWidget *viewport)
    {
        QGLWidget *glWidget = dynamic_cast<QGLWidget*>(viewport);
        if (glWidget)
            glWidget->updateGL();
    }

};
baysmith