[PyQt] QGLWidget c++ widget works, SIP binding doesn't

Josh Knox jknox at irobot.com
Wed Apr 28 20:13:02 BST 2010


Josh Knox wrote:
> Hi All,
>
> I've got a simple custom QGLWidget that works fine when loaded from 
> c++. (basically the Sierpinski demo)
>
> I've built a SIP binding against it, that I can load from python but 
> it only ever displays a black area and it appears that the event loop 
> never starts.
>
> My SIP file is trivial:
>
>    %Import QtCore/QtCoremod.sip
>    %Import QtGui/QtGuimod.sip
>
>    %Import QtOpenGL/QtOpenGLmod.sip
>    %Module MyGLTest 0
>
>
>    class MyGLWidget : QGLWidget
>    {
>    %TypeHeaderCode
>    #include "../MyGLTest/include/QtGLTest.hpp"
>    #include <QGLWidget>
>    %End
>
>    public:
>             MyGLWidget(QWidget* parent /TransferThis/ = 0, const 
> QGLWidget*
>    shareWidget = 0, Qt::WindowFlags f = 0);
>
>    };
>
> My Python script to show it is also trivial (essentially equivalent to 
> the C++ code to do the same):
>
>    import sys
>    from PyQt4 import QtGui
>    from MyGLTest import MyGLWidget
>
>    if __name__ == "__main__":
>
>        app = QtGui.QApplication(sys.argv)
>
>        # test the simple GL widget
>        myGLWidget = MyGLWidget()
>        myGLWidget.resize(400, 350)
>        myGLWidget.setWindowTitle('MyGLWidget')
>        myGLWidget.show()
>
>        app.exec_()
>
>
> This just launches a Qt window with an all black widget area.
>
> So, given that the C++ widget works, what could I be missing that's 
> prevent the SIP binding from running properly?
>
> I'm still new at this, so any ideas appreciated!
>
>
> Thanks,
>
> Josh
> _______________________________________________
> PyQt mailing list    PyQt at riverbankcomputing.com
> http://www.riverbankcomputing.com/mailman/listinfo/pyqt

Hmm, after lots of researching and building SIP bindings for various 
widgets I've discovered some strange behavior.

It appears that for any QWidget class I make in C++, when loaded from 
python via SIP bindings, the top-level/parent widget does not receive 
any events. If I place children on a container QWidget in another C++ 
class and make bindings for that, then the widget does show up and work 
properly.

If, in Python, I create a Qwidget and then place my custom widget on it, 
it does not work; again receives no events.

I've reproduced this behavior with multiple custom widgets that I have 
created. The code below demonstrates this problem.
The ColorSlider class is my widget. It just paints on the QWidget directly.

ColorSliderX is a widget that contains a ColorSlider.

When created in python, ColorSlider does not update or receive events.  
When created via ColorSliderX, the child ColorSlider works fine.

I'm still kinda new at this so I might be missing something really 
obvious, but I have no idea what. My workaround by nsting the widget in 
the C++ implementation will get me working for now but it seems really 
wrong to have to do this.

Any ideas what I'm missing?

Thanks,

Josh


============= HEADER =============

#ifndef QTPY_H
#define QTPY_H

#include <QtGui/QtGui>
#include <QtGui/QPaintEvent>
#include <QtGui/QResizeEvent>
#include <QtGui/QWheelEvent>
#include <QtGui/QWidget>

// colorful slider widget test class
class ColorSlider : public QWidget
{
    Q_OBJECT

public:
    ColorSlider(QWidget *parent=0);
    virtual ~ColorSlider();

public:
    QSize sizeHint()        const { return QSize(100,300); }
    QSize minimumSizeHint() const { return sizeHint();     }

public slots:
    void setValue(int value);

signals:
    void valueChanged(int value);

protected:
    virtual void paintEvent(QPaintEvent* event);
    virtual void resizeEvent(QResizeEvent* event);
    virtual void wheelEvent(QWheelEvent *event);

private:
    int m_temp;
    QTransform m_xform;
    bool m_mdrag;
};

/* This class is a workaround to get the ColorSlider to show up with 
PyQt. */
class ColorSliderX : public QWidget
{
    Q_OBJECT
public:
   
    ColorSliderX(QWidget *parent=0);
    virtual ~ColorSliderX();

    // The child widget
    ColorSlider *slider;

};

#endif // QTPY_H




============= CPP =============

/*  ColorSlider & ColorSliderX implementation.
#include "qtpy.h"
#include <iostream>

ColorSlider::ColorSlider(QWidget *parent)
:   QWidget(parent),
    m_temp(50),
    m_mdrag(false)
{
    std::cerr << "ColorSlider::ColorSlider()" << std::endl;
    show();
}

ColorSlider::~ColorSlider()
{
    std::cerr << "ColorSlider::~ColorSlider()" << std::endl;
}

void ColorSlider::setValue(int value)
{
    std::cerr << "ColorSlider::setValue(" << value << ")" << std::endl;

    if (value != m_temp) {
        if (value < 0)
            m_temp = 0;
        else if (value > 100)
            m_temp = 100;
        else
            m_temp = value;

        emit valueChanged(m_temp);
        update();
    }
}

void ColorSlider::paintEvent(QPaintEvent* event)
{
    std::cerr << "ColorSlider::paintEvent()" << std::endl;

    QColor color(0,255,0);
    if (m_temp > 50) {
        color.setRedF((m_temp - 50)/50.0);
        color.setGreenF((100 - m_temp)/50.0);
    }
    else if (m_temp < 50) {
        color.setGreenF(m_temp/50.0);
        color.setBlueF((50.0 - m_temp)/50.0);
    }

    QPainter painter(this);
    painter.setPen(QPen(Qt::NoPen));
    painter.setBrush(QBrush(color));
    painter.setWindow(0, 0, 100, 100);
    painter.translate(0, 100);
    painter.scale(1, -1);
    painter.drawRect(0,0,100,m_temp);

    m_xform = painter.combinedTransform();
}

void ColorSlider::resizeEvent(QResizeEvent* event)
{
    std::cerr << "ColorSlider::resizeEvent(" << width() << ", " << 
height() \
        << ")" << std::endl;
}

void ColorSlider::wheelEvent(QWheelEvent *event)
{
    if (event->delta()>0 && m_temp<100) {
        std::cerr << "ColorSlider::wheelEvent(SCROLL_UP)" << std::endl;
        setValue(m_temp + 1);
    }
    else if (event->delta()<0 && m_temp>0) {
        std::cerr << "ColorSlider::wheelEvent(SCROLL_DOWN)" << std::endl;
        setValue(m_temp - 1);
    }
}


/* The parent container */
ColorSliderX::ColorSliderX(QWidget* parent):
    QWidget(parent), slider(new ColorSlider(this))
{
    slider->show();
    std::cerr << "ColorSliderX::ColorSliderX()" << std::endl;
}

ColorSliderX::~ColorSliderX()
{
    std::cerr << "ColorSliderX::~ColorSliderX()" << std::endl;
}


============== SIP =============
%Module QtPy 0

%Import QtCore/QtCoremod.sip
%Import QtGui/QtGuimod.sip

class ColorSlider : QWidget
{
%TypeHeaderCode
#include "../QtTest/QtPy/qtpy.h"
%End

public:
    ColorSlider(QWidget* parent /TransferThis/ = 0);
    ~ColorSlider();
   
public slots:
    void setValue(int value);

signals:
    void valueChanged(int value);
};

class ColorSliderX : QWidget
{
%TypeHeaderCode
#include "../QtTest/QtPy/qtpy.h"
%End

public:
    ColorSliderX(QWidget* parent /TransferThis/ = 0);
    ~ColorSliderX();
    ColorSlider* slider;
   
};




More information about the PyQt mailing list