[PyQt] QGLWidget c++ widget works, SIP binding doesn't
Phil Thompson
phil at riverbankcomputing.com
Wed Apr 28 22:08:15 BST 2010
On Wed, 28 Apr 2010 15:13:02 -0400, Josh Knox <jknox at irobot.com> wrote:
> 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;
>
> };
One thing you haven't done (though it might not make a difference in this
case) is to provide %ConvertToSubClassCode.
Phil
More information about the PyQt
mailing list