[Kde-bindings] Hacking moc-generated code

Eric Jardim ericjardim at gmail.com
Fri Sep 9 17:49:25 UTC 2005


2005/9/9, Richard Dale <Richard_Dale at tipitina.demon.co.uk>:
> 
> You need some syntax to emit a signal:
> emit foobar("hello", 5)


Ok. I was thinking in nothing special:
>>> button.clicked()
or
>>> button.signal_clicked()

But we can do something like:
>>> button.emit('clicked()', (,) )
Or
>>> button.emit('clicked(bool)', (True,) )

So emit() would be a method which doesn't actually do anything, then 
> foobar()
> might actually map onto a common method for all signals. You then look at 
> the
> current stackframe to find the name of the actual ruby method, then look 
> up
> it's id number via the QMetaObject.


Hmm, don't like this part. I think this is not safe, I say, we can have 
functions pointing to functions (adapters) and it could mess up. Well, I 
just think "button.emit" is more simple. 


Yes, it's better to have exactly the same syntax for using both python and 
> C++
> signals.


It is not just about sintax. PYSIGNALs don't exist in C++ world. This means 
you can't embedded it back in C++. In python-qt4 it is already possible, 
with no headaches.

Oops, typo make that just 1000 classes.


Sure, but is still a lot o classes. I am thinking about it. But this sounds 
to me we must work on a parser, or to tweak a existing parser, to be able to 
read the QObjects and understand those macros like Q_PROPERTY, Q_INTERFACE, 
Q_INFO.

I mean, in Python things are a little different:
C++:
button->setVisible(true);
std::cout<< button->isVisible() << std::endl;

Python:
>>> button.visible = True
>>> print button.visible 
True

Right now, it is only possible because I say to Boost.Python that 
"setVisible" and "isVisible" are setter and getter of a "visible" a 
property. "Dumb" scripts will never discover it. That's what I say about 
being more Pythonic. Well part of the hole story.

That sounds interesting. I'm pretty sure your shouldn't have to intervene to
> make the binding more pythonic


Not just more Pythonic, but more interesting. For example, there is no point 
in wrapping the QString class. Python have a "unicode" and "str" class that 
work pretty well. Instead of wrapping everything, we write custom converters 
that do it transparently:

In old SIP/PyQt:
>>> button = QPushButton(u'Ok', None) # entered a unicode
>>> button.text() # this is a QString, no unicode.
<__main__.qt.QString object at 0xf7f7b630>

In new python-qt4:
>>> button = QPushButton(u'Ok', None)
>>> button.text # a propery, no need to ()
u'Eric' # a real genuine Python unicode object, ready for i18n 

Yes, it sounds worth experimenting with.


Yes, but I think we (binders) must work together in a single parse of a 
QObject child class header. That would be good for everyone. Maybe the Smoke 
project

Smoke is a language independent auto generated library used by the QtRuby 
> and
> PerlQt bindings at the moment. 


Sounds tasty. Where can I find Smoke for Qt4?


It could be used by java, C# and possibly
> python too. At the moment its main problem is that it's too monolithic, 
> and
> everything is all in one big library. 


Java and C# are not "scripting" languages. I see no point porting Qt to 
those (no offenses). Well, maybe the guys who write the bindings have some 
good points, but I just can't see it. Well, if I want static typing I can 
continue with good old C++. 

I think new Qt4/Smoke will be very interesting. Maybe the code I wrote for 
python-qt4 help in something.


It stands for 'Scripting Meta Object
> Kompiler Engine', and is a sort of 'moc on steroids' - it adds an
> introspection layer for the complete api, and a language independent way 
> of
> invoking methods dynamically, or virtual methods callbacks.


Nice. 


Yes, that's the idea. Otherwise, you need a large library for each language,
> instead of a single wrapper library like Smoke, with a smaller 'adaptor'
> layer for each language. 


Hmm, should think more about it. Need to learn more.


A future version of Smoke could use the Qt4 moc
> format, but include ordinary methods as well as signals and slots, along 
> with
> a way of adding virtual method callbacks so you can override them in the
> scripting language.
> 

That's easy to do with Boost.Python. The problem is find a way of doing it 
for all "script" languages.

I just not agree with that part of "turn all ordinary method signals and 
slots". If you think better, it will "polute" the interface of the object. 
Beside this, signals and slots can be overloaded, so if you want to use it 
with embedded C++ or with other binding, you should do combinatorial job 
with the args!

I mean "clicked(bool)" and "clicked()" stantds for the same slot. But this 
is just a single C++ method. Now imagine how do you expose 
"my_custom_method(self, begin, end, *args, **kw)"? There is no type 
information here.

My current idea (I may change it) is:

- If we want to expose a signal (so even QtDesigner can read it), we must 
say it, and which types. Ex:
class MyWidget(QObject):
@signal('int, int') # this is a Python decorator. You can do it the old way, 
too.
def textChanged(begin, end):
...
# valid for the class

- If we want to expose a slot (same as above):
@slot('QString')
def setHeader(text):
...
# valid for the class

- If we want to connect any kind of signal to a QObject method, we promote 
that method to a slot, with the signature you used to connect it:
>>> sender_qobject.connect('clicked(bool)', reciever_qobject.method)
# now reciever_qobject's MetaObject register a new slot signed as 
'method(bool)', 
# incremental use of the thing (not poluted)
# if the (promoted) slot is connect again with the same signature, it is 
ignored. 
# if a new one signature is used register the new one (eg. 'method()')
# this is valid for the instance.

- If we want to connect any kind of signal to a function, ordinary method, 
or lambda expression, python-qt4 create s a dummy fake QObject 
(transparently) that proxies the signal for you:

>>> sender.connect('clicked()', reciever.method) 
>>> sender.connect('clicked()', a_function)
>>> sender.connect('clicked()', lambda: QApplication.quit() )

# inside python-qt4 (transparent)
class FakeSlot(QObject):
def __init__(self, destiny):
self.destiny = destiny # python callable
def callback(self, *args, **kw):
self.destiny(*args, **kw) # redirect the call

>>> fakeslot = FakeSlot(my_callable)
>>> sender.connect('clicked(bool)', fakeslot.callback)

Nice, eh?

[Eric Jardim]
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.kde.org/pipermail/kde-bindings/attachments/20050909/e17161ef/attachment.html>


More information about the Kde-bindings mailing list