[PyKDE] sip, was: newest Version

Phil Thompson phil at riverbankcomputing.co.uk
Sat Nov 1 15:47:00 GMT 2003


On Saturday 01 November 2003 2:14 pm, Roland Schulz wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On Saturday 01 November 2003 13:19, Phil Thompson wrote:
> > On Saturday 01 November 2003 8:37 am, Roland Schulz wrote:
> > > -----BEGIN PGP SIGNED MESSAGE-----
> > > Hash: SHA1
> > >
> > > Hey,
> > >
> > > On Saturday 01 November 2003 00:25, you wrote:
> > > > On Friday 31 October 2003 9:49 pm, Roland Schulz wrote:
> > > > > -----BEGIN PGP SIGNED MESSAGE-----
> > > > > Hash: SHA1
> > > > >
> > > > > Hey,
> > > > >
> > > > > trying to change the sip layer makes great advancement. Overwriting
> > > > > the className function already makes the Preview working!!
> > > > > Overwriting metaObject also makes signals, slots and propterties
> > > > > (partly) working!! So I think this will work.
> > > >
> > > > How have you "overwritten" the className function?
> > >
> > > Adding it to sipqtQWidget.h by hand. See the attached file.
> > >
> > > > > What I did for className is that I added to sipqtQWidget.h:
> > > > > virtual const char *className() const {return "FileChooser";}
> > > > >
> > > > >
> > > > > How should I do this in qwidget.sip? How can I get the classname
> > > > > (of course harding it is only for testing)? Calling className from
> > > > > Python space gives the correct result, so this should be doable.
> > > > > How can I access variables defined in the Python claass? Is there a
> > > > > way to tell sip to add this className method to all classes?
> > > >
> > > > Use the /AutoGen/ option to automatically generate methods, but I'm
> > > > not convinced this is going to help.
> > >
> > > What does this /AutoGen/ function?
> >
> > Having seen what you've done, /AutoGen/ isn't designed for what you want
> > to do. It needs a SIP change to generate the calls.
>
> Could this be done easily?

Yes - just look through sipgen/gencode.c to find where the relevant code is 
being generated and add the new stuff.

> > > > Remind me how Designer calls the factory
> > > > function to create the widget.
> > >
> > > designer creates an object PyQWidgetPlugin from the library and calls
> > > the create method. Create uses pythonize to call the createWidget
> > > method in the Python class.
> >
> > I agree with Jim in that I can't see why adding these functions here is
> > any different to using a proxy.
>
> The problem is not adding the functions to the proxy but to create a
> working proxy. May be I just don't get how to create such a proxy easily.
> What I did, is: I took the header files for QWidget (I want to proxy
> QWidget), QObject and QPaintDevice. The later two are the base classes so I
> tought there methods also have to be proxyed. But it still didn't work and
> I think the problem is that these classes have:
> QApplication  QBaseApplication  QDragManager  QETWidget  QFontInfo
> QFontMetrics  QLayout  QPaintDeviceMetrics  QPainter  QSignal  QWSManager
> QWidget
> as friend classes. So there I think I would also have to proxy all private
> methods and I don't know how to find out if anyone directly access some
> member variables. So I don't know how to create a QWidget proxy. If I would
> have one, I could do there the changes as easily, but I don't get so far.
> Is there an easier/other way to create such an proxy? Otherwise I don't
> think this is a good way to go.

The proxy doesn't need to proxy for the whole QWidget API - just the parts 
used by Designer. I would expect that to be a very small subset.

> > In the end you are going to need to introspect
> > the Python object to return the correct class name and meta-object
> > anyway. (However I am coming round to thinking the proxy approach is
> > worse as a more general solution.)
>
> agree
>
> > I think what you need to do next is to come up with 2 functions that can
> > go into the SIP module/library that can be called from SIP generated code
> > (or a proxy) like this...
> >
> > class sipQFoo : public QFoo
> > {
> > public:
> >     const char *className() const
> >     {
> >         return sipGetClassNameForCpp(sipPyThis);
> >     }
> >
> >     QMetaObject *metaObject() const
> >     {
> >         static QMetaObject *metaObj = 0;
> >
> >         if (!metaObj)
> >             metaObj = sipGetMetaObjectForCpp(sipPyThis);
> >
> >         return metaObj;
> >     }
> >
> >     ...normal ctors...
> >
> > In fact sipGetClassNameForCpp() is fairly simple...
> >
> > const char *sipGetClassNameForCpp(sipThisType *sipThis)
> > {
> >     PyObject *nmo;
> >
> >     if (sipThis == NULL || (nm = sipClassName((PyObject *)sipThis)) ==
> > NULL) return "Unknown class";
> >
> >     const char *nm = PyString_AsString(nmo);
> >     Py_DECREF(nmo);
> >
> >     return nm;
> > }
> >
> > You can do the other one. :)
>
> I'll try. But it would already be very nice only to have the classname
> function. Like I wrote, this makes already the Preview working.
>
> How can I access variables defined in the Python class?

Use Python's C API.

> To get properties working I'll need to also overwrite qt_property. Than I
> can see if they work.

I don't understand why - I would expect the default implementation to return 
the correct meta-data and there is no additional data to add from a Python 
sub-class.

> For signals and slots we'll need to do same changes to pyuic too.
> For the connection
>     <connection>
>         <sender>fileChooser1</sender>
>         <signal>fileNameChanged(const QString&amp;)</signal>
>         <receiver>fileChooser2</receiver>
>         <slot>setFileName(const QString&amp;)</slot>
>     </connection>
>
> it creates:
> self.connect(self.fileChooser1,SIGNAL("fileNameChanged(const
> QString&)"),self.fileChooser2,SLOT("setFileName(const QString&)"))
>
> but has to generate:
> self.connect(self.fileChooser1,PYSIGNAL("fileNameChanged"),self.fileChooser
>2.setFileName)
>
> in the case of a Python class. Of course it has to know if it is a python
> class, but it could get this information from the Comment line.
>
> Than we need to discuss what syntax we want to use to define signals and
> slots in the Python class. One problem is that designer only connects
> signals and slots with fiting arguments, so we have to pass the information
> about the arguments to.
> What do you think about a syntax like:
> class FileChooser:
> 	Q_SIGNALS = [["fileNameChanged","QString"]]
> 	Q_SLOTS = [["setFileName","QString"],["chooseFile"]]
> 	def __init__ .....
>
> Both are lists of lists of strings. One List for every sinal/slot and the
> first entry of the list is the name. The following the arguments.

Why bother with the argument types seeing as Python is dynamically typed?

Given that any Python callable is a possible slot, I don't see the point of 
restricting the set that Designer is told about.

Anyway, the syntax is irrelevant to me - it's only the library function you 
write that needs to know about it.

Phil




More information about the PyQt mailing list