[Kde-bindings] Qyoto: SIGNALS/SLOTS
Richard Dale
Richard_Dale at tipitina.demon.co.uk
Mon Jan 16 20:31:18 UTC 2006
On Monday 16 January 2006 18:53, Arno Rehn wrote:
> Hi,
>
> as I have absolutely no clue how to get signals and slots working with
> QMetaObjects, I have another idea:
Well, we just need to copy the QtRuby code for constructing them on the fly,
but derive the signal and slot names via C# reflection. For signals, we look
at the IQApplicationSignals interface or what ever, and for slots we go
through the methods via reflection looking for which ones are marked with
Q_SLOT. Then a Qyoto class which has been subclassed, would return a
QMetaObject with those extra slots/signals from the QObject.MetaObject()
method call. Then when there is a qt_invoke() virtual method callback, it
would need to know if it was calling C# slots or C++ ones. If C#, then it
does something similar to a virtual method callback. If C++ it just calls the
qt_invoke() method in the superclass, which would in turn call a C++ slot.
> With the unsafe keyword, the documentation says, we can code normal C in
> C#, so I wondered if we could do something like Qt#'s libqtsharp (yeah, I
> know again it's Qt#...), but dynamically and in the C#-code. Maybe it would
> be possible do create something like a moc but for C#, which creates code
> for each class containing the methods for connecting a signal to a slot...
It isn't any harder to do what I've described above, I'm sorry I haven't
explained what needs doing very well.
Here's what I've been doing this weekend, maybe have a look at this code? I
haven't finished it, but maybe you can help. The reflection call needs to
obtain this dummy constructor:
[SmokeClass("QApplication")]
public class QApplication : QObject, IDisposable {
protected QApplication(Type dummy) : base((Type) null) {}
interface IQApplicationProxy {
So the code below works, but it will get any non-public constructor, rather
than the one with the specific arg of 'Type dummy'. I couldn't work out how
to use 'GetConstructor()' for protected constructors:
// CreateInstance() creates a wrapper instance around a C++ instance which
// has been created in C++ code, and not via a Qyoto C# constructor call.
// It takes the class name string and obtains its Type. Then it finds the
// dummy constructor which takes a Type as an arg, like this for example:
//
// protected QWidget(Type dummy) : base((Type) null) {}
//
// The constructor is run to create the wrapper instance. Then the method
// to create the transparent proxy to forward the method calls to
// SmokeInvocation.Invoke() is called. In the case of the QWidget
// example above, this method would be called 'CreateQWidgetProxy()'.
static IntPtr CreateInstance(string className) {
Type klass = Type.GetType(className);
ConstructorInfo[] constructorInfo = klass.GetConstructors(
BindingFlags.NonPublic
| BindingFlags.Instance
| BindingFlags.DeclaredOnly);
Type[] constructorParamTypes = new Type[1];
constructorParamTypes[0] = Type.GetType("System.Type");;
// ConstructorInfo constructor =
klass.GetConstructor(constructorParamTypes);
if (constructorInfo[0] == null) {
Console.WriteLine("CreateInstance(\"{0}\") constructor method missing
{1}", className, constructorParamTypes[0]);
return (IntPtr) 0;
}
object result = constructorInfo[0].Invoke(new object []
{ constructorParamTypes[0] });
Console.WriteLine("CreateInstance(\"{0}\") constructed {1}", className,
result);
Type[] paramTypes = new Type[0];
MethodInfo proxyCreator = klass.GetMethod("CreateProxy",
BindingFlags.NonPublic
| BindingFlags.Instance
| BindingFlags.DeclaredOnly);
if (proxyCreator == null) {
Console.WriteLine("CreateInstance() proxyCreator method missing");
return (IntPtr) 0;
}
proxyCreator.Invoke(result, null);
return (IntPtr) GCHandle.Alloc(result);
}
I'll check in what I have anyway. This will fix the problem of not being able
to wrap C# instances around C++ instances that have been created within C++,
rather than via ordinary qyoto C# constructors.
-- Richard
More information about the Kde-bindings
mailing list