[PyKDE] Sugestions for PyQt4

Eric Jardim ericjardim at gmail.com
Mon Mar 20 13:26:27 GMT 2006


Hi, I want to make some sugestions for PyQt4. It will be good if people
comment them, as some of this ideais may be not good or just imcomplete. In
advance, sorry if my english is bad. I could also speak Japanese if you want
:)


- No more QStrings and QByteArray: As Python have good support for unicode
strings, there is no need for this objects appear in Python. All conversions
should be done internally and automatically.
I've made some progress with this and it may help:
http://svn.berlios.de/viewcvs/python-qt4/trunk/Core/QString.cpp?view=markup
http://svn.berlios.de/viewcvs/python-qt4/trunk/Core/QByteArray.cpp?view=markup

Beside this, the way one translate applications will change a bit (see
below).


- Better support for the "tr" function:  As was sugested before in the list,
the "tr" function could be installed as a __builtins__ function. We can use
the stack to determine the context, with no need to sacrifice pyuic4 or
pylupdate4.

If we are using python unicode strings, them we have to change the idiom of
"tr". Instead of:
>>> print tr(u"There are %1 files on the %2 folder").arg(n).arg(s)
We could change to:
>>> print tr(u"There are %1 files on the %2 folder", (n, s))
We can pass a tuple of arguments, in the right order.

If one are using gettext, so he have nothing to worry. But I think
pylupdate4 should also support it.


- "Pythonic" Qt properties: instead of using things like: "isEnabled()" and
"setEnabled()", properties could be acessed like python real properties, I
mean, just "enabled". The functions could still be mapped anyway.

I don't know how SIP works (automatically or handmade), and it will give a
lot of work to acomplish this "by hand". I've have made some progress with a
tool called pygccxml, that can parse C++ code and find Qt properties and
other Qt special macros (with some tricks).

- C++ embedding: it may be useful for some users to embed Python plugins in
an C++ application. This could be a "magic gate" for some "static"
applications that want to be more flexible. There should be some limitations
to this technique, but if we can easily use Python obejcts in C++
applications. Remember that we have to connect C++ signals/slots to Python
signal/slots (see dynamic metaobjects below).


- QtDesigner integration: I think this is a dream of everyone to make your
custom widgets available in QtDesigner. With the new Qt4 API, it is very
easy to write plugins for QtDesigner.

The problem of the QtDesigner approach is that you have to create a share
object (plugin library) for each component you may add to the Widget Box
(palette). I thought of a single approach of creating a generic
QPythonWidget (a proxy) that internally calls your custom real Python
extension. Plus, we must adapt the
QtUiTools::QUiLoader (http://doc.trolltech.com/4.1/quiloader.html) and
pyuic4 to load the Python widget correctly. A scratch of this can be found
here:
http://svn.berlios.de/viewcvs/python-qt4/trunk/PythonQt/

By the way, to be fully useful, our Python widgets should expose their
SIGNALs, SLOTs and properties to QtDesigner (and native C++ classes if
embedded), and this means a new way of facing metaobjects (see below).

- Dynamic metaobjects:
The metaobjects are the internal information of every QObject derived
object. This information is used by Qt to give C++ the flexibility it does
not have naturally (they use moc to do the "dirty" job). Besides, it also
gives some power of introspection. All of the Qt extensions to the C++
language, like Signals, Slots and Properties, does not really exist in C++,
but they are recoreded on its owner metaobject.

When you create a new class, derived from QObject (or any other like QWidget
and so on), moc (meta object compiler) creates a "static" metaobject,
describing the class. I mean static in two meanings: it is static (is the
same) for every object the class, and do not change with time (like const).
This is Ok for C++ extensions, but Python widgets may change durring the
execution of the program. We can add new signals, slots or properties
class-wide or object-wide. This makes the complexity grows a little bit.

My progress over this is here:
http://svn.berlios.de/viewcvs/python-qt4/trunk/PythonQt/QtWrapper.h?view=markup

With this feature, we can use Python signals inside QtDesigner, inside a C++
embedded python application and we can treat all of them the same way
(goodbye PYSIGNAL). The way things are today, there is no way declare a
Python signal. You just know it exist when you emit it. OTOH, any method in
your class can be a slot. This is fine, but how do you want to expose your
class to someone? How do you tell that just some of your methods are really
meant to be slots?


- The new Signal, Slot, Property idom:
With all this changes, it should be nice to define the a way to declare our
QObject classes extensions. My sugestion is the simples as possible:

from PyQt4 import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class MyWidget(QWidget):
    # how to define a slot
    def aSlot(sender, text):
        ...
    aSlot = QSLOT(aSlot, 'QObject, str')

    # how to define a signal
    def aSignal(message):
        ...
    aSignal = QSIGNAL(aSlot, 'str')

    # how to define a property
    def pSet(value):
        ...
    def pGet():
        ...
    p = QPROPERTY(pGet, PSet, ...)  #look: p is a Qt and Python property!

In Python 2.4 we can also have sintax sugar:
class MyWidget(QWidget):
    @QSLOT('QObject, str')
     def aSlot(sender, text):
        ...

     @QSIGNAL('str')
    def aSignal(message):
        ...

Sweet, hu? So you got the idea.  But you may also have noticed that I
declared the types of the params. Some people may not like this. But think
that, in some cases, there is no way of guessing what kind of slot you are
talking about, unless you specify the types (remember Qt have some slots
with same name, but different types). It will help with QtDesigner
integration.

But I still think someone should not be obligated to declare something like
C++ pointers or const to QObjects in Python just to have this kind of
signal/slot. Let's see below.


- Smart flexible connections
Why should I connect this:
>>> connect(a, SIGNAL('aSignal(QObject*,const QString&, int)'), b.aSlot)
When I can do this:
>>> connect(a, SIGNAL('aSignal(QObject, str, int)'), b.aSlot)

The "connect" function should be smarter and do things like this. Of course
this have some limitations, but most of the cases will work ok. OObject is
not copyable, so you will never pass a QObject (or any other derived) by
value. So when I know that QObject (or any other derived) is in fact a Qt
special class, I will just connect internally with 'QObject*'. But the user
does not have to care. This also should be applied to SLOT(...).

But we know that most of the cases, we have no overloaded slots, so why not:
>>> connect(a, SIGNAL('aSignal'), b, SLOT('aSlot'))
or
 >>> connect(a, SIGNAL('aSignal'), b.aSlot)
or even (my favorite)
>>> connect(a.aSignal, b.aSlot)

This will depend of the case, of course. We may treat with native C++ signal
and slots. There are some possible combinations and the introspection of the
params will help here.


- How to deal with Qt Intefaces?
Not thought about this yet.


Well, here we have a good start. There are other little things, but let's
focus on this first :)
Hope you enjoy and this be useful for the PyQt project.

--
Eric Jardim
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20060320/e083f507/attachment.html


More information about the PyQt mailing list