[Kde-bindings] Qyoto: SIGNALS/SLOTS
Arno Rehn
arno at arnorehn.de
Fri Dec 9 19:42:56 UTC 2005
Am Freitag, 9. Dezember 2005 20:16 schrieb Richard Dale:
> On Friday 09 December 2005 16:47, Arno Rehn wrote:
> > Am Donnerstag, 8. Dezember 2005 21:58 schrieb Richard Dale:
> > > On Thursday 08 December 2005 19:32, Arno Rehn wrote:
> > > > Am Mittwoch, 7. Dezember 2005 17:43 schrieb Richard Dale:
> > > > > On Wednesday 07 December 2005 15:36, Arno Rehn wrote:
> > > > > > Hi,
> > > > > >
> > > > > > I experimented a bit and created a more complex Hello-World
> > > > > > sample app. I wanted to connect the "clicked()" signal of a
> > > > > > button to the "quit()" slot of QApplication. Got a SIGSEGV.
> > > > > > I looked into the Qt.cpp of qtruby and it seems as signals and
> > > > > > slots are a bit difficult.
> > > > >
> > > > > QtRuby dynamically constructs QMetaObjects, rather than it being
> > > > > done at compile time by the moc pre-processor. But the actual
> > > > > runtime is identical. We need a way of denoting which methods are
> > > > > slots in C#, and I assume we can use 'attributes' (or are they
> > > > > called
> > > > > 'annotations' I've forgotten). Maybe you could have a look at how
> > > > > we might mark slots, and then the runtime side should be very
> > > > > similar to QtRuby. We don't have to invent anything much new apart
> > > > > from that.
> > > >
> > > > OK, I found out how to mark Signals/Slots with Attributes. I attached
> > > > an example.
> > >
> > > That looks good. In Qt4 there is a macro 'Q_SLOTS' to use instead of
> > > the 'slots' moc keyword because of a clash with the Boost library. So
> > > maybe slots could be marked like this, to look more like that macro:
> > >
> > > [Q_SLOT()]
> > > public void mySlot()
> > > {
> > > }
> > >
> > > Maybe signals need to map onto delegates, rather than ordinary methods.
> >
> > Would be a good idea. Maybe signals need to be delegates, which are set
> > by the programmer or 'QObject.Connect()'. Could look like this:
> >
> > public class QApplication : ...
> > {
> > delegate void LastWindowClosedHandler();
> >
> > [Q_SIGNAL()]
> > LastWindowClosedHandler LastWindowClosed;
> >
> > ...
> > }
>
> Yes, and I think it would need to have a string with the C++ type
> signature, like the Q_SLOT example I give below:
>
> [Q_SIGNAL("void lastWindowClosed()")]
> LastWindowClosedHandler LastWindowClosed;
>
> > Now we could just say 'LastWindowClosed' is set by the programmer. This
> > would keep the delegate-system of Mono/.NET. Additionally it would be
> > possible to create a 'QObject.Connect(...)' which dynamically connects
> > 'LastWindowClosed' to another method. But I don't know how to check
> > whether the underlying C++-instance triggered the signal. Then it would
> > be quite easy to call the appropiate delegate.
>
> We don't want to dynamically connect the delegate to target slots because
> the Qt runtime will do that. But we would need to trap the LastWindowClosed
> delegate call and then raise the Qt signal inside the Qyoto runtime. I need
> to read up more on how delegates work. Should the Q_SIGNAL attribute be
> against the delegate declaration?
>
> [Q_SIGNAL("void lastWindowClosed()")]
> delegate void LastWindowClosedHandler();
>
> > > At the moment an interface is generated containing the type signatures
> > > of signals like this:
> > >
> > > public interface IQApplicationSignals {
> > > void LastWindowClosed();
> > > void AboutToQuit();
> > > void GuiThreadAwake();
> > > }
> > >
> > > And I was thinking of having a QObject.Emit() method which returned a
> > > transparent proxy, so you could invoke a signal with like this:
> > >
> > > (LastWindowClosed) myInstance.Emit()
>
> I got this wrong, it should look like this:
>
> ((IQApplicationSignals) myInstance.Emit()).LastWindowClosed();
>
> And the interface for a class would need to extend the signals interface
> for its superclass. So in the case above the IQApplicationSignals interface
> would need to extend the IQObjectSignals interface. But this doesn't really
> fit in with delegates.
>
> > > And it would be forwarded to SignalInvocation.Invoke(), in a similar
> > > manner to how ordinary method calls get diverted to
> > > SmokeInvocation.Invoke() at the moment.
> > >
> > > But slots are easiest to get working first though, and marking them
> > > with attributes like you've done looks pretty good to me.
>
> I think the slots need to be marked as slots, along with the C++ type
> signature that would be used for constructing the QMetaObject entry for it.
> Like this:
>
> using System;
> using System.Reflection;
>
> [AttributeUsage( AttributeTargets.Method )]
> class Q_SLOT : Attribute
> {
> public string signature;
>
> public string Signature
> {
> get
> {
> return signature;
> }
> }
>
> public Q_SLOT(string signature)
> {
> this.signature = signature;
> }
> }
>
> public class main : Object
> {
> public static void Main(string[] args)
> {
> new main();
> }
>
> public main()
> {
> MethodInfo miSlot = this.GetType().GetMethod( "mySlot" );
> Console.WriteLine( GetAttributeName( miSlot ) );
>
> object[] attributes;
> attributes = miSlot.GetCustomAttributes(typeof(Q_SLOT), false);
> if (attributes.Length > 0) {
> Q_SLOT slotAttr = (Q_SLOT) attributes[0];
> Console.WriteLine( "Q_SLOT signature: {0}", slotAttr.Signature );
> }
>
> }
>
> [Q_SLOT("void mySlot(QString)")]
> public void mySlot(string arg)
> {
> }
>
> public string GetAttributeName( MethodInfo mi )
> {
> Attribute[] attr = ( Attribute[] ) mi.GetCustomAttributes( true );
>
> if( attr.Length < 1 )
> return null;
>
> Type t = attr[0].GetType();
> return t.Name;
> }
> }
Looks good, but do you want to connect a C++-signal to a C++-slot? The
C++-slots are methods in C#, so we don't really need C++ type signatures, do
we?
If you want to connect C++ to C++ the signatures should be there of course.
--
MfG
Arno Rehn
arno at arnorehn.de
More information about the Kde-bindings
mailing list