Connect QML signal to C++11 lambda slot (Qt 5)



  • Hello everyone,

    New QtQuick user here and having a jolly nice time so far!

    There is one question, however, for which I haven't managed to find the answer so far in the documentation. Imagine that you have a QML object that defines a signal like this:

    @Rect {
    id: bar
    name: "bar"
    signal foo();
    property string baz;
    }
    @

    and you want to connect it to a slot that is not part of a QObject:

    @auto root = qml_container.rootObject(); // returns the Rect defined above
    root->connect(root, "foo()", = { std::cout << "foo!" << std::endl; });@

    Unfortunately, this fails because there is no connect() overload that takes a string signal and a function pointer slot. The new syntax can only take a function pointer signal and function pointer slot:

    @root->connect(root, &SomeQObject::foo, = { /* whatever */ });@

    But the QML signal is not defined as part of a concrete QObject known at compile-time (that's the reason of using QML in the first place!)

    So what I would like to do is access the QML signal by querying the container object at runtime:

    @auto prop = root->property("baz"); // works for properties
    auto sig = root->???("foo"); // what's the correct API for this?@

    From what I can tell so far, if I could somehow get a pointer to the foo QML signal I should be able to connect it to a lambda slot. Does anyone have any ideas?

    (The rationale behind this: clean separation between UI defined in QML and handlers defined in C++. I don't wish to define a QObject for every QML signal if I can somehow avoid it.)

    Question originally asked here: http://stackoverflow.com/questions/15624800/connect-qml-signal-to-c11-lambda-slot-qt-5


  • Moderators

    Use the old syntax. That will kill the lambda, but I don't think there is another solution. You might try finding something in QMetaObject but I a quick look tells me it won't help you.

    Or connect in JavaScript.



  • A signal is just a method. You can use the QMetaMethod accessors to find it. isSignal() should return true.
    It's early in the morning and I haven't fully woken up yet, so I might be wrong.

    Cheers,
    Chris.



  • Indeed! I can use a QMetaMethod to access the signal at runtime and connect it to a QMetaMethod slot.

    Unfortunately, it's not possible to get a QMetaMethod for a non-QObject slot (so no lambdas or free functions), which means I'm still stuck with the same problem: I cannot connect a QML signal to a lambda slot...

    For the moment, I have developed an ugly workaround where I encapsulate the slot function into a SignalRouter class derived from QObject. This works, but is both in-elegant and a maintenance burden: for every different QML signal signature, I have to add a corresponding C++ signature to the SignalRouter class (huge "container class" smell). Templates might help here but, of course, MOC does not support templated QObjects so this is a no-go.

    I'm starting to think that what I'm trying to do is simply impossible (at least in a clean way) given the current Qt 5 APIs. Does anyone know if Qt 5.1 adds any new functionality regarding signal-slot connections?



  • I really can't answer that, to be honest. Stephen Kelly might know, Thiago certainly would, so you could try asking on #qt on freenode.

    Cheers,
    Chris.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.