[Qt-interest] invalid drawable with Cocoa/QGLWidget

Alan Norton alan at ucar.edu
Fri Feb 26 23:27:28 CET 2010


Oliver,
I have found a workaround for this, but it's a real kludge.    I can 
call hide() on the QGLWidget when it's first created, and then call 
show() when it is truly exposed (by checking its position relative to 
the scrollbar).  I tried altering the resizeEvents but that didn't 
work.  Evidently the context is set up after, not during the 
resizeEvent.  showEvent didn't help either.  I regard this as a Qt bug 
since there is no API exposed to the user to enable one to properly 
initialize a scrolled qglwidget.
-Alan

On 2/26/10 4:14 AM, Oliver.Knoll at comit.ch wrote:
> Alan Norton wrote on Thursday, February 25, 2010 11:28 PM:
>
>    
>> Karl,
>> InitializeGL() does get called, well before the "invalid drawable"
>> message.  I think that the problem is that initializeGL gets called
>> too early, before the window can be displayed.
>>      
> If it is really the GL context which causes trouble, then it is not the fault of initializeGL being called too early. As I wrote in another post initializeGL is only called just before the first resizeGL is to be called. But the GLContext is already created at *construction* time of the QGLWidget (you can even pass along a "self-made" QGLContext into the c'tor of the QGLWidget), and that is typically when the application starts and creates the main window etc.
>
>    
>> In Cocoa, the context
>> needs to get enabled at a time when the window can be drawn.
>>      
> What exactly do you mean with "enabled"? Is that the same like "created"? Thinking about it again, I don't think it is a problem that the QGLContext is "created" before the QGLWidget is displayed - because this is also the case in my application (and any other GL application):
>
> And if you look at the Qt code:
>
> QGLWidget::QGLWidget(QWidget *parent, const QGLWidget* shareWidget, Qt::WindowFlags f)
>      : QWidget(*(new QGLWidgetPrivate), parent, f | Qt::MSWindowsOwnDC)
> {
>      Q_D(QGLWidget);
>      setAttribute(Qt::WA_PaintOnScreen);
>      setAttribute(Qt::WA_NoSystemBackground);
>      setAutoFillBackground(true); // for compatibility
>      d->init(new QGLContext(QGLFormat::defaultFormat(), this), shareWidget); //<-- QGLContext is created here
> }
>
> So I don't think the problem is the time of QGLContext creation here. Because in my application, at the time when above QGLWidget/QGLContext c'tor is called my QGLWidget is also not visible.
>
> But I think it is more the QGLContext::makeCurrent() method which might give trouble if the widget is not visible.
>
>    
>>    I
>> think I need
>> to postpone the initializeGL and other OpenGL preparation until the
>> window is ready to display.  Unfortunately I don't know how to do
>> that.
>>      
> initializeGL() is only called when the widget receives its first resize event. Here is the stack trace I get on Windows (must the the same like on Mac, because no platform-specific code is called, until the actual makeCurrent() implementation:
>
>    QtOpenGLd4.dll!QGLContext::makeCurrent()  Zeile 1159	C++<-- Windows specific code here
>    QtOpenGLd4.dll!QGLWidget::makeCurrent()  Zeile 3518	C++
>    QtOpenGLd4.dll!QGLWidget::glInit()  Zeile 4053	C++
>    QtOpenGLd4.dll!QGLWidget::resizeEvent(QResizeEvent * __formal=0x0012c990)  Zeile 1340	C++
>    QtGuid4.dll!QWidget::event(QEvent * event=0x0012c990)  Zeile 8133	C++<-- at this point the widget is just about to be displayed
>    ...
>
> I believe that the problem is in the point of time when the Mac-specific code in QGLContext::makeCurrent() is called.
>
> And I think the resize() is called from the layout manager, and it does this for every widget, regardless of them being visible or not (because it needs to calculate the sizes of the widgets for the layout).
>
>    
>> Qt tries to use the GL context when the containing widget is
>> first drawn, even though the QGLWidget is not visible, which results
>> in the error. -Alan
>>      
> So my previous suggestion - only paint the visible widgets - would not help, because resize() would still be called from the layout manager at the point when the "container" widget (the one which is set as viewable area in the QScrolllArea) is to be displayed.
>
> A terrible workaround could hence be to
>
> - override QGLWidget::resizeEvent()
>
> - in resizeEvent(), don't call the "super" method QGLWidget::resizeEvent(), unless the widget is "visible"
>    (tricky: how to find out whether the widget is visible in the QScrollArea?)
>
> - Once the QGLWidget becomes visible, only then call the QGLWidget::resizeEvent() method
>
>
> So the basic idea would be to try to defer the call to QGLWidget::resizeEvent until the first paint event is received:
>
> // override resize()
> void MyQGLWidget::resizeEvent(QResizeEvent *event) {
>    if (isVisibleWithinScrollArea()) {
>      QGLWidget::resizeEvent(event);
>      m_resizeEvent = 0;
>    } else {
>       m_resizeEvent = event;
>    }
> }
>
> void MyQGLWidget::paintGL() {
>    if (m_resizeEvent != 0)
>      // deferred resize
>      QGLWidget::resizeEvent(m_resizeEvent);
>    }
>    ...
> }
>
> Maybe that would work?
>
>
> Cheers,
>    Oliver
>    



More information about the Qt-interest-old mailing list