[PyKDE] Re: newest Version

Roland Schulz mail at r2s2.de
Thu Oct 30 09:17:01 GMT 2003

Hash: SHA1

On Wednesday 29 October 2003 23:40, you wrote:
> On Wednesday October 29 2003 12:22, Roland Schulz wrote:

> > > I'm certainly willing to generate any necessary additional
> > > bindings, and Phil is willing to do some PyQt changes, but
> > > at least in my case, I'm not sure of what's really
> > > necessary. It seems to me this can all be done most easily
> > > in C++ inside the plugin, so I must be missing something
> > > (again).
> >
> > Please discribe how you think it can be done in the plugin.
> > Like I wrote previously, I think that this can't be done. The
> > problem I see is: The lib creates an object and afterwards
> > qtdesigner has this object and just calls the methods it wants
> > to. How do you want to intercept there?
> OK - here's my theory:
> You code a new widget in Python with a base class of QWidget (or
> QObject) or some Q* class that has QWidget/QObject (QLayout
> stuff is QObject-based). To be able to use that widget in
> QtDesigner (abbreviated QtD - too much typing) you need to
> create a .so plugin in some manner (more below about that). The
> plugin has to actually instantiate the widget, so it calls a
> factory function.
> (I get a little fuzzy here - I'd like to be able to test this to
> be certain - so correct me if I'm wrong.)
> When you call the factory function, you call into Python and get
> a PyObject * back. The actual Python widget doesn't have a
> corresponding C++ object that actually exists, but it must have
> a C++ base class instance that exists (QWidget/QObject if
> nothing else). Once you have the PyObject *, you can do a sip
> conversion (sipForceConvertTo_xyz) to get a C++ pointer,
> probably to a base class. This points to a real C++ object
> instance that sip has created from the Qt libs.
> The C++ object has a metaObject () method that will give you
> access to it's meta data. You can use the QMetaObject pointer
> returned, plus the methods in qmetaobject.h and qucom_p.h to add
> the Python meta data (which the Python programmer has to specify
> when he creates his widget using something like a dict or
> dicts). THEN you return to QtD the *base class* pointer with
> complete meta data for the Python subclass. That takes care of
> the meta data part.
There are two problem. First there aren't any public methods to change the 
metaObject. Public avaiable is only the constructor which sets all the 
informations. Secondly the QMetaObject created for a class is shared by all 
objects of this class. So in case you would change the QMetaObject of the 
QWidget baseclass of your phyton class you would also change the QMetaObject 
of all other running QWidget objects.
So I see no other way than changing the metaObject method, so that not the 
shared QMetaObject is returned, but a new created one. This can either be 
done by subclassing as David proposed or by changing the sip layer.

> When QtD wants to manipulate the object it's received from the
> plugin, it only has the base class pointer BUT the virtual
> method table associated with the base class pointer contains
> pointers (effectively) to the the *Python* overloaded methods.
> (That's one of the questions I asked Phil previously - assuming
> I stated the question understandably, he indicated that was
> correct). QtD is only going to call methods for painting,
> geometry management, etc. I don't think QtD is smart enough to
> have any arbitrary knowledge of how your widget operates. For
> example, if you create a QListView and want to add
> QListViewItems to it, you have to pop up a QListViewItem editor
> dialog which is hardcoded into QtD. I assume from that case that
> QtD only really knows enough to place and draw the widgets you
> layout - you need to write additional extensions for other
> functionality. That should mean that a base class pointer should
> be sufficient.
I think this is correct, currently there is no way to create something like 
the ListView Editor for a custom widget, because it is hardcorded into 
qtdesigner itself and not a function of ListView. So you would have to change 
qtdesigner itselft to add such a function to qtdesigner. 

> So at this point (assuming I'm right, which may not be a good
> assumption), you have all the meta data you need for the
> connection editor dialog/signal handler tab, any properties, and
> nethods for painting/sizing/placing.
Well there are these two problems above why changing the MetaObject won't work 
I think.

> What I don't know is:
> Suppose the base class is QLineEdit which is:
>     QObject
>         QWidget
>             QFrame
>                 QLineEdit
>                     PyWidget
> Does it make a difference which type the factory function
> returns?  I'm not sure about the meta data - each class adds
> more slots, signals and properties. If you get
> QWidget::metaObject(), will you get the QFrame and QLineEdit
> meta data too? Finding the "topmost" Q* class might be difficult
> - if required, it might be necessary to either have the Python
> programmer specify it or have an external piece of code (in
> Python - better introspection) determine it and set it in the
> C++ files that create the plugin.
Currently calling className or metaObject from C++ space for a Python object 
gives the information of the direct C++ super class of the Python class, so 
it is easy to find this out.

> If I'm wrong about this, I'm wrong about the virtual method table
> and meta data (as in the previous paragraph). It shouldn't be
> hard to test - just write something that calls the factory
> function and then dump the meta data that's available, see what
> methods get called, etc. I haven't looked at how a virtual
> method table actually works in *years*. If I'm wrong about that,
> then the next suggestion will have to come from Phil, because it
> gets into what sip does now and what sip can/can be made to
> provide. If it doesn't work the way I think it does, you're
> going to need a layer between QtD and the widget that's
> effectively C++ bindings for the Python code.
Could we also overwrite which function is called for a call to the metaObject 
method throught the virtual method table? Than this be a possiblity too.

> The other issue is whether each Python-created widget (or group
> of widgets in a module) needs a unique .so lib for its plugin,
> or it's possible to create a single "proxy" plugin that will
> handle any Python-created widget. The KPanelApplet
> implementation in PyKDE does the "proxy", but the KDE
> architecture for most plugins (KControl, KParts, etc) requires a
> .so lib for each plugin (more or less) with some specific naming
> constraints.
I don't see a reason other than maybe the MetaObject problem why this should 
be necessary so we should avoid this if possible.

> In either case, I'd like to see a PyQt GUI app that guides the
> user in constructing the C++ files needed - David has the KParts
> stuff set up so that the user can:
I still hope we won't need any C++ files created from the user.


> 1. "Fill in the blanks" in the GUI for a few items, like plugin
> name
> 2. The GUI app can write out the appropriate C++ files, mostly by
> using a skeleton and altering some #defines.
> 3. The GUI app can also generate the pro file and call qmake (and
> could call make and make install too I suppose).
> 4. It would also be useful to provide a "test harness" for the
> Python-created widget - based on my personal screwups with panel
> applets, it's important to know that the widget is syntactically
> correct and can actually be constructed before trying to get the
> plugin to work. Enforced testing would probably save a lot of
> questions and "bug" reports (along with good docs).
> > So I think this has to be done in the sip code.
> > What I think should be done is (all in C++ space):
> >
> > - - Add an static QMap to sipQObject containing all
> > QMetaObject's for all loaded Python classes (the index can be
> > the classname or some id). - - Add to the constructor of
> > sipQObject:
> > 	- check if the QMetaObject for this Python class is already
> > constructed - if not create the QMetaObject. The data is read
> > out from variables in the Python class
> > - - Add the method metaObject (so this version is called from
> > C++ space, its not needed from Python space)
> > 	it looks for its class QMetaObject in the QMap and returns it
> Sounds right to me.
> > Questions:
> > Are the additions to the constructor and to metaObject
> > automatically for all subclasses of QObject?
> >
> > Why is the call of the method classname for a Python class
> > from the C++ space not giving its name?
> >
> > How can we find out the classname of the Python class in the
> > constructor and in the metaobject method?
> >
> > How can we access the variables in the Python class containing
> > the meta Data?
> For example:
> Python
> =====
> 	SLOTS = {}
>         SLOTS ["quit"] = [ ... ]  # some formatted list or tuple
> C++
> ===
>     PyObject *pyslots = pythonize.getNewObjectRef (moduleName,
>           "SLOTS");
>     if (!PyDict_Check (pyslots)) error ();
>     PyObject *keys = PyDict_Keys (pyslots);
>     int count = PyList_Size (keys);
>     for (int i = 0; i < count; i++)
>     {
> 	    PyObject *key = PyList_GetItem (keys, i);
>             char *keyStr   = PyString_AsString (key);
>             PyObject *values = PyDict_GetItem (pyslots, key);
>             // 'values' is most likely a Python list or tuple.
>             // process it here into whatever parameters you need
>             // based on the format you create for specifiying
>             // meta data in Python (slot arguments or whatever);
>             // stuff it into the metaObject
>             ...
>     };
> That's all just a convenience for QtDesigner's connection
> editor/signal handler tab - anything can be a slot in Python but
> it seems like a good idea to let the programmer identify what he
> intended as a slot.
> > How can we add the metaObject method but only
> > for calls from c++ space?
> >
> > I hope that this isn't complete nonsense. ;-)
> Same here - I tend to figure this stuff out by writing code, not
> by writing about code, and that catches most of my errors.
> Jim
Version: GnuPG v1.2.2-rc1-SuSE (GNU/Linux)


More information about the PyQt mailing list