[PyKDE] embedding python widgets in C++ app

Patrick Stinson patrickkidd.lists at gmail.com
Wed Jan 24 00:04:12 GMT 2007


With regards to the PyQt4 package and python's inittab, what is wrong
with the following code?

 struct _inittab builtin_modules[] = {
   { "sip", initsip },
   { "PyQt4.QtCore", initQtCore },
   //    { "QtGui", initQtGui },
   { NULL, NULL }
 };
 PyImport_ExtendInittab(builtin_modules);

 printf("*** Initializing Python...");
 Py_Initialize();
 printf(" done.\n");

 PyRun_SimpleString("import PyQt4.QtCore");


running the code above I get the following:

*** Initializing Python... done.
Traceback (most recent call last):
 File "<string>", line 1, in ?
ImportError: No module named PyQt4.QtCore


It says in the python docs that the name set in the struct _inittab
should match that passed to Py_InitModule, which in this case is
PyQt4.QtCore. What am I forgetting?
- Hide quoted text -


On 1/22/07, Patrick Stinson <patrickkidd.lists at gmail.com> wrote:
> On 1/22/07, Phil Thompson <phil at riverbankcomputing.co.uk> wrote:
> > 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.
>
> cool! I would never have thought of that.
>
> >
> > > > > 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.
>
> Ahhh... ok. That's something I can deal with. That will simplify
> building and linking sip into the app as well.
>
> >
> > > Considering pyqt modules are nomral python 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?
> >
>
> funny. one-small-step-at-a-time. Getting the custom interpreter in
> there with the pyqt modules will make a big difference.
>
> "Resistance is futile - you will be assimilated"
>
> > Phil
> >
>
>
> --
> Patrick Kidd Stinson
> http://www.patrickkidd.com/
> http://pkaudio.sourceforge.net/
> http://pksampler.sourceforge.net/
>


--
Patrick Kidd Stinson
http://www.patrickkidd.com/
http://pkaudio.sourceforge.net/
http://pksampler.sourceforge.net/




More information about the PyQt mailing list