[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