[review] [PyKDE] Extraction of Qt objects from a PyObject

Albert Strasheim albert at dogbert.sdsl.sun.ac.za
Mon Feb 9 13:12:00 GMT 2004


Hello,

Thanks, I'll take a look. Have the functions you mention been added in a
recent version of SIP? I'm currently using sip 3.8 and PyQt 3.8 as shippped
with Fedora Core 1.

Cheers,

Albert

----- Original Message ----- 
From: "Jim Bublitz" <jbublitz at nwinternet.com>
To: <midcom at execpc.com>; "Albert Strasheim (by way of Therese Bublitz
<midcom at execpc.com>)" <13640887 at sun.ac.za>; <jim at first.creek>
Sent: Sunday, February 08, 2004 6:45 PM
Subject: Re: [review] [PyKDE] Extraction of Qt objects from a PyObject


> On Sunday February 8 2004 08:23, Albert Strasheim wrote:
> > Hello PyKDE mailing list,
> >
> > I am writing some code that intercepts the events received by
> > a Qt program by installing an event filter on the QApplication
> > instance.
> >
> > When events are intercepted, they are passed on to another
> > object via a call to a function. This function is pure
> > virtual, so you can derive a C++ or Python class from it to
> > specify a function to do with the events what you want.
> > Alternatively, the event filter can call another function
> > which returns an object, the class of which is derived from
> > QEvent, to inject new events which the program must handle.
> >
> > I'm using Boost.Python to wrap the "event handler" base class,
> > but I would like to use the existing SIP Qt bindings instead
> > of writing my own. I'm currently having a problem extracting
> > the events (i.e. instances of the classes derived from QEvent)
> > from the PyObject* returned by the latter function mentioned
> > above.
> >
> > The Python code looks like this:
> >
> > from qt import *
> > from pyqttest import *
> >
> > class PyEventHandler(EventHandlerBase):
> >     def __init__(self):
> >         EventHandlerBase.__init__(self)
> >         pass
> >     def inject(self):
> >         return QKeyEvent(QEvent.KeyRelease, 0, 32, 0, 'h',
> > False, 0)
> >
> > def main():
> >     eh = PyEventHandler()
> >     myQtAppTest = MyQtAppTest(TestType.INJECT, eh)
> >
> > The C++ wrapper around the base class that PyEventHandler is
> > deriving from looks like this:
> >
> > struct EventHandlerBaseWrap : MyUnitTest_t::EventHandlerBase_t
> > {
> >    EventHandlerBaseWrap(PyObject* self_) :
> >       self(self_)
> >    {
> >    }
> >
> >    virtual QEvent* inject()
> >    {
> >       try
> >       {
> >          // Get a Python object
> >          boost::python::object o = call_method<object>(self,
> > "inject");
> >
> >          // more code here...
> >       }
> >       catch (...)
> >       {
> >          // something has gone badly wrong...
> >       }
> >    }
> > }
> >
> > MyUnitTest_t::EventHandlerBase_t::inject() is a pure virtual
> > function.
> >
> > boost::python::object is a Boost.Python type that wraps around
> > a PyObject*. You can get at the underlying PyObject* by
> > calling the object's ptr() method.
> >
> > If I print the QKeyEvent instantiated in the Python inject()
> > above (i.e. the __repr__ method is called?), the address
> > displayed corresponds to the address contained in the pointer
> > returned by object's ptr() method, so I'm pretty sure the
> > return is working. Now I need to get at the event in the
> > PyObject so that I can copy it and return the address of the
> > copy:
> >
> > boost::python::object o = call_method<object>(self, "inject");
> > int iserrp = 0;
> > PyObject* attr_name = PyString_FromString("__class__");
> > PyObject* baseclass = PyObject_GetAttr(o.ptr(), attr_name);
> > delete attr_name;
> > attr_name = 0;
> >
> > const QEvent* e = reinterpret_cast<const QEvent*>(
> >     sipConvertToCpp(o.ptr(), baseclass, &iserrp));
> >
> > I obtained this way of figuring out the base class from a
> > thread on this mailing list in July 2003. I'm not sure this is
> > exactly what I want to do here, though. Now that we have the
> > QEvent (or maybe it's a sipQEvent? of course, the
> > reinterpret_cast isn't going to care), we call the type()
> > method to figure out the derived type so that we may copy all
> > its information:
> >
> > switch ( e->type() )
> > {
> >     case QEvent::KeyPress:
> >     case QEvent::KeyRelease:
> >     {
> >         std::cout << "QEvent* = " << e << std::endl;
> >         std::cout << typeid(e).name() << std::endl;
> >         std::cout << typeid(*e).name() << std::endl;
> >         const QKeyEvent* k = dynamic_cast<const
> > QKeyEvent*>(e); std::cout << "casted const QKeyEvent* = " << k
> > << std::endl; }
> >
> >     // ...
> > }
> >
> > When run, this code prints out the following:
> >
> > QEvent* = 0x923c108
> > PK6QEvent
> > 12sipQKeyEvent
> > casted const QKeyEvent* = 0
> >
> > The interesting one is the third line. Apparently the
> > underlying object is a sipQKeyEvent, and not a QKeyEvent.
> > Also, the dynamic_cast fails, so apparently sipQKeyEvent is
> > not derived from QKeyEvent. From what I can see, sipQKeyEvent
> > is not declared in any public headers.
> >
> > How do I go about extracting the underlying QKeyEvent so that
> > I can do with it what I want? Am I going about the whole the
> > wrong way? Is sipConvertToCpp() the function I want to call
> > here? Am I using the right value for baseclass?
>
> The method you want is:
>
> QKeyEvent *sipForceConvertTo_QKeyEvent (PyObject *,  int *);
>
> and is found in sipqtQKeyEvent.h in PyQt*/qt, where PyQt* is the
> directory you build PyQt in. You also need to link to
> libqtcmodule.so (-L<install dir> -lqtcmodule). Usage, where 'p'
> is a ptr to the PyObject to convert, is:
>
> // should eliminate having to do the #include
> extern QKeyEvent *sipForceConvertTo_QKeyEvent (PyObject *,
> int *);
>
> int isErr = 0;
> QKeyEvent *qk = sipForceConvertTo_QKeyEvent (p, &isErr);
> if isErr:
> <error occurred>
>
> I don't know anything about the boost related stuff, so can't
> comment on that.
>
> Jim




More information about the PyQt mailing list