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 :)<br>
<br>
<br>
- 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.<br>
I've made some progress with this and it may help:<br>
<a href="http://svn.berlios.de/viewcvs/python-qt4/trunk/Core/QString.cpp?view=markup">http://svn.berlios.de/viewcvs/python-qt4/trunk/Core/QString.cpp?view=markup</a><br>
<a href="http://svn.berlios.de/viewcvs/python-qt4/trunk/Core/QByteArray.cpp?view=markup">http://svn.berlios.de/viewcvs/python-qt4/trunk/Core/QByteArray.cpp?view=markup</a><br>
<br>
Beside this, the way one translate applications will change a bit (see below).<br>
<br>
<br>
- Better support for the &quot;tr&quot; function:&nbsp; As was sugested before in
the list, the &quot;tr&quot; 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.<br>
<br>
If we are using python unicode strings, them we have to change the idiom of &quot;tr&quot;. Instead of:<br>
<font size="1"><span style="font-family: courier new,monospace;">&gt;&gt;&gt; print tr(u&quot;There are %1 files on the %2 folder&quot;).arg(n).arg(s)</span></font><br>
We could change to:<br>
<font style="font-family: courier new,monospace;" size="1">&gt;&gt;&gt; print tr(u&quot;There are %1 files on the %2 folder&quot;, (n, s))</font><br>
We can pass a tuple of arguments, in the right order.<br>
<br>
If one are using gettext, so he have nothing to worry. But I think pylupdate4 should also support it.<br>
<br>
<br>
- &quot;Pythonic&quot; Qt properties: instead of using things like: &quot;isEnabled()&quot;
and &quot;setEnabled()&quot;, properties could be acessed like python real
properties, I mean, just &quot;enabled&quot;. The functions could still be mapped
anyway. <br>
<br>
I don't know how SIP works (automatically or handmade), and it will
give a lot of work to acomplish this &quot;by hand&quot;. 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).<br>
<br>
- C++ embedding: it may be useful for some users to embed Python
plugins in an C++ application. This could be a &quot;magic gate&quot; for some
&quot;static&quot; 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).<br>
<br>
<br>
- 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. <br>
<br>
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 <br>
QtUiTools::QUiLoader (<a href="http://doc.trolltech.com/4.1/quiloader.html">http://doc.trolltech.com/4.1/quiloader.html</a>) and
pyuic4 to load the Python widget correctly. A scratch of this can be
found here:<br>
<a href="http://svn.berlios.de/viewcvs/python-qt4/trunk/PythonQt/">http://svn.berlios.de/viewcvs/python-qt4/trunk/PythonQt/</a><br>
<br>
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).<br>
<br>
- Dynamic metaobjects:<br>
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 &quot;dirty&quot; 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.<br>
<br>
When you create a new class, derived from QObject (or any other like
QWidget and so on), moc (meta object compiler) creates a &quot;static&quot;
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.<br>
<br>
My progress over this is here:<br>
<a href="http://svn.berlios.de/viewcvs/python-qt4/trunk/PythonQt/QtWrapper.h?view=markup">http://svn.berlios.de/viewcvs/python-qt4/trunk/PythonQt/QtWrapper.h?view=markup</a><br>
<br>
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?<br>
<br>
<br>
- The new Signal, Slot, Property idom:<br>
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:<br>
<br>
<font size="1"><span style="font-family: courier new,monospace;">from PyQt4 import *<br>
</span></font><font size="1"><span style="font-family: courier new,monospace;">from PyQt4.QtCore import *</span></font><br style="font-family: courier new,monospace;">
<font size="1"><span style="font-family: courier new,monospace;"></span><span style="font-family: courier new,monospace;">from PyQt4.QtGui import *</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">class MyWidget(QWidget):<br>
&nbsp;&nbsp;&nbsp; # how to define a slot<br>
&nbsp;&nbsp;&nbsp; def aSlot(sender, text):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br>
&nbsp;&nbsp;&nbsp; aSlot = QSLOT(aSlot, 'QObject, str')<br>
</span></font><font size="1"><span style="font-family: courier new,monospace;"><br>
</span></font><font size="1"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; # how to define a signal<br>
</span></font><font size="1"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; def aSignal(message):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br>
&nbsp;&nbsp;&nbsp; aSignal = QSIGNAL(aSlot, 'str')<br>
<br>
</span></font><font size="1"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; # how to define a property<br>
</span></font><font size="1"><span style="font-family: courier new,monospace;"></span></font><font size="1"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; def pSet(value):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br>
&nbsp;&nbsp;&nbsp; def pGet():<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br>
&nbsp;&nbsp;&nbsp; p = QPROPERTY(pGet, PSet, ...)&nbsp; #look: p is a Qt and Python property!<br>
</span></font><br>
In Python 2.4 we can also have sintax sugar:<br>
<font size="1"><span style="font-family: courier new,monospace;">class MyWidget(QWidget):<br>&nbsp;&nbsp;&nbsp; @Q</span></font><font size="1"><span style="font-family: courier new,monospace;">SLOT('QObject, str')</span></font><br>
<font size="1"><span style="font-family: courier new,monospace;">
&nbsp;&nbsp;&nbsp; def aSlot(sender, text):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br></span></font><font size="1"><span style="font-family: courier new,monospace;"><br>
</span></font><font size="1"><span style="font-family: courier new,monospace;"></span></font><font size="1"><span style="font-family: courier new,monospace;">
&nbsp;&nbsp;&nbsp; @QSIGNAL('str')<br>
</span></font><font size="1"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; def aSignal(message):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br><br>
</span></font><font size="1"><span style="font-family: courier new,monospace;"></span></font>Sweet,
hu? So you got the idea.&nbsp; 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.<br>
<br>
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.<br>
<br>
<br>
- Smart flexible connections<br>
Why should I connect this:<br>
<font style="font-family: courier new,monospace;" size="1">&gt;&gt;&gt; connect(a, SIGNAL('aSignal(QObject*,const QString&amp;, int)'), b.aSlot)<br>
</font>When I can do this:<br>
<font style="font-family: courier new,monospace;" size="1">&gt;&gt;&gt; connect(a, SIGNAL('aSignal(QObject, str, int)'), b.aSlot)<br>
</font><br>
The &quot;connect&quot; 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(...).<br>
<br>
But we know that most of the cases, we have no overloaded slots, so why not:<br>
<font style="font-family: courier new,monospace;" size="1">&gt;&gt;&gt; connect(a, SIGNAL('aSignal'), b, SLOT('aSlot'))<br></font>or<br>
<font style="font-family: courier new,monospace;" size="1">
</font><font style="font-family: courier new,monospace;" size="1">&gt;&gt;&gt; connect(a, SIGNAL('aSignal'), b.aSlot)</font><br>
or even (my favorite)<br>
<font style="font-family: courier new,monospace;" size="1">&gt;&gt;&gt; connect(a.aSignal, b.aSlot)<br>
</font><br>
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.<br>
<br>
<br>
- How to deal with Qt Intefaces?<br>
Not thought about this yet.<br>
<br>
<br>
Well, here we have a good start. There are other little things, but let's focus on this first :)<br>
Hope you enjoy and this be useful for the PyQt project.<br>
<br>
--<br>
Eric Jardim<br>