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):
    @Q
SLOT('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
_______________________________________________
PyKDE mailing list    [email protected]
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde

Reply via email to