[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