Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Connect QML signal to C++11 lambda slot (Qt 5)
Forum Update on Monday, May 27th 2025

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

Scheduled Pinned Locked Moved QML and Qt Quick
7 Posts 5 Posters 6.5k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    Black Star
    wrote on last edited by
    #1

    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

    1 Reply Last reply
    0
    • sierdzioS Offline
      sierdzioS Offline
      sierdzio
      Moderators
      wrote on last edited by
      #2

      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.

      (Z(:^

      1 Reply Last reply
      0
      • C Offline
        C Offline
        chrisadams
        wrote on last edited by
        #3

        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.

        1 Reply Last reply
        0
        • B Offline
          B Offline
          Black Star
          wrote on last edited by
          #4

          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?

          1 Reply Last reply
          0
          • C Offline
            C Offline
            chrisadams
            wrote on last edited by
            #5

            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.

            1 Reply Last reply
            0
            • D Offline
              D Offline
              DiKouti
              wrote on last edited by
              #6

              Few years later, still no QMetaMethod::toSignalFunc(), poor onTheFly us !

              But a solution exists though. You can create a unique slot to create all your QmlToLambda connection instead of roouting each signal trought a C++ declared slot.
              Something like:
              connect(root, qmlSig, this, QMetaMethod::fromSignalFunc(&Interface::myUniqueCppSlotForAllConnections);

              And the implementation for the slot would be something like:
              void Interface::myUniqueCppSlotForAllConnections(QString) {
              if(!properties().contains(name)){
              (*properties()[name])(){
              //whatever
              }

              1 Reply Last reply
              0
              • fcarneyF Offline
                fcarneyF Offline
                fcarney
                wrote on last edited by fcarney
                #7

                Use the Connections object to connect to a signal on a known C++ object (setContextProperty or similar). Have that signal be connected to your lambda in C++.

                Edit:
                You don't need the Connections object.

                class SignalHolder : public QObject
                {
                    Q_OBJECT
                public:
                    SignalHolder(){}
                
                signals:
                    void relaySignal(QString msg);
                };
                
                ...
                
                QQmlApplicationEngine engine;
                
                    SignalHolder sh;
                    sh.connect(&sh, &SignalHolder::relaySignal, [](QString msg){
                        qDebug() << "relay message:" << msg;
                    });
                
                    auto context = engine.rootContext();
                    context->setContextProperty("signalholder", &sh);
                

                In QML:

                Item {
                        id: qmlsignalholder
                
                        signal relayMessage(string message)
                
                        Component.onCompleted: {
                            relayMessage.connect(signalholder.relaySignal)
                
                            relayMessage("Hello Signal")
                        }
                    }
                

                C++ is a perfectly valid school of magic.

                1 Reply Last reply
                0

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved