views:

309

answers:

1

Hello, I was wondering if it was possible to share widgets between PyQt and Boost.Python.

I will be embedding a Python interpreter into an application of mine that uses Qt. I would like users of my application to be able to embed their own UI widgets into UI widgets programmed in C++ and exposed via Boost.Python.

Is this possible and how would one go about doing this?

+1  A: 

I've tried to write some proxying for this, but I haven't succeeded completely. Here's a start that tries to solve this, but the dir() won't work. Calling functions directly works somewhat.

The idea was to create an additional python object wrapped in SIP and forward any calls/attributes to that object if the original boost.python object does not have any matching attribute.

I'm not enough of a Python guru to make this work properly, though. :(

(I'm turning this into a wiki, so ppl can edit and update here, as this code is just half-baked boilerplate.)

c++:

#include "stdafx.h"    
#include <QtCore/QTimer>

class MyWidget : public QTimer
{
public:
    MyWidget() {}
    void foo() { std::cout << "yar\n"; }
    unsigned long myself() { return reinterpret_cast<unsigned long>(this); }
};

#ifdef _DEBUG
BOOST_PYTHON_MODULE(PyQtBoostPythonD)
#else
BOOST_PYTHON_MODULE(PyQtBoostPython)
#endif
{
    using namespace boost::python;

    class_<MyWidget, bases<>, MyWidget*, boost::noncopyable>("MyWidget").
        def("foo", &MyWidget::foo).
        def("myself", &MyWidget::myself);
}

Python:

from PyQt4.Qt import *
import sys

import sip
from PyQtBoostPythonD import * # the module compiled from cpp file above

a = QApplication(sys.argv)
w = QWidget()
f = MyWidget()

def _q_getattr(self, attr):
  if type(self) == type(type(MyWidget)):
    raise AttributeError
  else:
    print "get %s" % attr
    value = getattr(sip.wrapinstance(self.myself(), QObject), attr)
    print "get2 %s returned %s" % (attr, value)
    return value

MyWidget.__getattr__ = _q_getattr

def _q_dir(self):
  r = self.__dict__
  r.update(self.__class__.__dict__)
  wrap = sip.wrapinstance(self.myself(), QObject)
  r.update(wrap.__dict__)
  r.update(wrap.__class__.__dict__)
  return r

MyWidget.__dir__ = _q_dir

f.start()
f.foo()
print dir(f)
Marcus Lindblom