[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