[PyKDE] embedding python widgets in C++ app

Phil Thompson phil at riverbankcomputing.co.uk
Mon Jan 22 20:03:35 GMT 2007


On Monday 22 January 2007 7:31 pm, Patrick Stinson wrote:
> On 1/22/07, Phil Thompson <phil at riverbankcomputing.co.uk> wrote:
> > On Monday 22 January 2007 9:21 am, Patrick Stinson wrote:
> > > oops, I think the title is backwards. I will send the author an email.
> > > I am trying to embed a python widget in a C++ application, where he is
> > > trying to access his C++ app code from his python code.
> > >
> > > I decided to manually import a module with a factory function, call
> > > that factory function from C++ and convert the python object to a
> > > QWidget * using sipConvertToInstance. After doing this, I have a few
> > > questions:
> > >
> > > What should the transfer object be as passed to sipConvertToInstance?
> > > I'm a little confused about the wording in the documentation, and
> > > sipTransferObj is automatically included if you are using this in a
> > > sip file.
> >
> > It depends on what you are going to do with the C++ instance (when is the
> > dtor going to be called) and it's Python object (when is it going to be
> > garbage collected). Do you want the C++ instance to outlive the Python
> > object?
>
> Well, I suppose it would crash if the C++ instance outlived the python
> object since the widget is defined in python. Is that right, or am I
> turned around?

The transfer object gives you control over when things happen. I think for 
your purposes you want to pass the Python object you are converting as the 
transfer object. This will create a circular dependency which will keep the 
Python object alive. The cycle should be broken by the C++ dtor.

> > > How are you supposed to statically link the PyQt libraries if you then
> > > lose the PyQt4 package, which initQtGui() expects to import QtCore
> > > from? initQtCore() works fine but initQtGui() fails looking for
> > > PyQt4.QtGui.
> >
> > PyQt modules are modules - they are not libraries. You do not link
> > against them. You can configure them as builtin modules, just like any
> > other module.
>
> Hmm ok. So you only recommend compiling them into a custom
> interpreter? Does this make sense with a primarily C++ app, with it's
> own entry point and source tree?

It's not simply a recommendation - you can't do it any other way and expect 
the results to be portable.

> Does that mean that linking against libpython.a, or the resulting
> python framework on mac will include the pyqt modules as builtins?

Yes.

> Considering pyqt modules are nomral pyhton modules I should probably
> just read mac-related docs for deploying C++ app bundles with embedded
> custom interpreters. That is the problem I'm facing afterall..
>
> I remember seeing an old document by you on how to build a custom
> interpreter with the pyqt3 sources. I guess I could follow those
> instructions again...
>
> > > Any comments on the following code?
> > >
> > >   char nameBuf[2048];
> > >   strcpy(nameBuf, moduleName);
> > >   PyObject *module = PyImport_ImportModule(nameBuf);
> > >   if(module)
> > >     {
> > >       PyObject *_create = PyObject_GetAttrString(module, "_create");
> > >       if(_create)
> > >         {
> > >           if(PyCallable_Check(_create))
> > >             {
> > >               PyObject *sipPy = PyObject_Call(_create,
> > > Py_BuildValue("()"), NULL);
> > >               if(sipPy)
> > >                 {
> > >                   int iserr = 0;
> > >                   QWidget *widget = reinterpret_cast<QWidget
> > > *>(sipConvertToInstance(sipPy, sipClass_QWidget, NULL, SIP\
> > > _NO_CONVERTORS, 0, &iserr));
> > >                   if(iserr == 0 && widget)
> > >                     {
> > >                       widget->show();
> > >                       qDebug("GOT WIDGET %p", widget);
> > >                       ret = widget;
> > >                     }
> > >                   else
> > >                     qWarning("could not sip => widget");
> > >                 }
> > >               else
> > >                 qWarning("error in _create return (%p)", sipPy);
> > >             }
> > >           else
> > >             qWarning("error \"_create\" is not callable");
> > >           Py_DECREF(_create);
> > >         }
> > >       else
> > >         qWarning("no attribute \"_create\"");
> > >     }
> > >   else
> > >     qWarning("no module \"pktest\"");
> >
> > Obviously you are leaking the sipPy and widget instances.
> >
> > The above code has to be part of a SIP generated module that %Imports
> > PyQt4.QtGui. The SIP API can only be called from SIP generated modules.
>
> Well, the function above would return the widget instance to code that
> would call QWidget::setParent(). The only goal is to write a widget in
> python and use it in my C++ app. If there is a better way..

...apart from writing everything in Python?

Phil




More information about the PyQt mailing list