[PyKDE] QtDesigner - simpler proxy
Jim Bublitz
jbublitz at nwinternet.com
Sun Nov 2 09:10:00 GMT 2003
It appears I've been thinking about doing proxying the hard way -
there's a much simpler way (really more a wrapper than a proxy):
proxyqwidget.h
===========
class ProxyQWidget : public QWidget
{
public:
ProxyQWidget (QWsiget *parent, const char *name,
const char *cls);
virtual const char *className () const { return clsName; }
virtual QMetaObject *metaObject () const;
private:
char *clsName;
};
proxyqwidget.cpp
=============
ProxyQWidget::ProxyQWisget (QWidget *parent, const char *name,
const char* cls)
: QWidget (parent, name)
{
clsName = new char [strlen (cls) + 1];
strcpy (clsName, cls);
}
QMetaObject *ProxyQWisget::metaObject
{
<manipulate the meta object here>
// You'll probably need another method to pull the meta data out
// of Python and the actual widget - I haven't done that
}
pyqwidgetplugin.cpp
===============
QWidget* PyQWidgetPlugin::create(const QString &key,
QWidget* parent,
const char* name)
{
if (debug) printf ("create %s\n", key.latin1 ());
PyObject* widgetModule = init(key);
// get the py factory function
PyObject *widgetFactory =
pyize->getNewObjectRef (widgetModule, "createWidget");
if (!widgetFactory) return pyqw_error ("***failed to find
widget factory\n");
//************************
//!!!!! create the proxy with the parent, name and key passed in
ProxyQWidget *pw = new ProxyQWidget(parent, name,
key.latin1 ());
// set up the args for the python factory function call
//************************
//!!!!! The proxy is passed as the parent of the Python widget
PyObject *pyParent = sipMapCppToSelf (pw,
sipClass_QWidget);
PyObject *args = Py_BuildValue ("Ns", pyParent,
name);
PyObject *pluginWidget = NULL;
if (pyParent && args)
{
// run the factory function
pluginWidget = pyize->runFunction (widgetFactory, args);
if (!pluginWidget) pyqw_error ("*** runFunction
failure\n;");
}
else if (debug)
pyqw_error ("***failed to create args\n");
// cleanup
pyize->decref (pyParent);
pyize->decref (args);
pyize->decref (widgetFactory);
QWidget *widget;
// convert the PyObject to a C++ PyQWidget *
int isErr = 0;
widget = sipForceConvertTo_QWidget (pluginWidget, &isErr);
if (isErr) return pyqw_error ("***failed sip conversion to
C++ pointer\n");
pyize->releaseLock ();
//************************
//!!!! Now just return the proxy as the parent of the Python
// widget
return pw;
}
This lets you set the class name, control the QMetaObject, and
fixes one other BIG problem I think the other approach ignored.
With the other approach (just embedding the Python widget and
doing all of the virtual method stuff), the proxy widget had no
children (I think that's why it always segfaulted for me). There
is NO general way to transfer the children to the proxy because,
as in the case of FileChooser, some of the children are QObjects
but not QWidgets (any QLayout descendents) and can't be
reparented - the approach above handles that (and is
considerably simpler besides).
Leaving ProxyQWidget parentless was probably causing a lot of the
earlier problems too.
I also made a few changes to pyqwidgetplugin.cpp - mostly some
refactoring (all the calls to the Pythonize ctor were driving me
nuts - you can replace them in 'init' with
pyize->acquireLock()).
I haven't played around with this much yet, but it seems to work
just fine. The one thing that needs to be done is that the
Python widget needs to provide size hints so that the proxy
widget can size itself properly - the "FileChooser" widget isn't
very pretty in QtDesigner without those, but it seems to work.
I feel a little silly not having thought of this earlier.
The other question is what this does to code generation. Haven't
looked at that either - that's likely to be a problem. It should
be possible to remove the extra widget layer from the generated
code ('cause I would think it's going to show up there).
Jim
More information about the PyQt
mailing list