Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Help with connect prototypes.



  • I am trying to add a class that will manage a signal and slot connection the idea is that class will have a connect method or possible two and a disconnect method.

    I know Qt Creator displays a helper when you start typing but this doesn't help me replicate the function prototypes. I currently use two in my application, one to connect a C++ signal:

        Object::connect(this  
                       ,&clsQPushBtn::clicked
                       ,[pobjScriptEng, strCall, strFile, strScript]() {
                           QString strScriptWithCall = static_cast<QString>(strScript)
                                                     + static_cast<QString>(strCall) + "();";
                           pobjScriptEng->evalulate(strScriptWithCall);
                       });
    

    Parameters:

        this is an instance of my PushButton class clsQtPushBtn
        clsQtPushBtn::clicked is the address of the "clicked" signal
        pobjScriptEng is a pointer to an instance of QJSEngine*
        strCall is a JavaScript function "test"
        strFile is the name of the JavaScript file "simon2.js"
        strScript is the content of the JavaScript file which contains the function test().
    

    The other connection method used:

        QObject::connect(this
                        ,&clsQtPushBtn::clicked
                        ,pobjSubscriber
                        ,&clsXMLnode::pbtnClicked);
    

    Parameters:

        this is an instance of my PushButton class clsQtPushBtn
        clsQtPushBtn::clicked is the address of the "clicked" signal
        pobjSubscriber pointer to the class that will received the signal
        clsXMLnode::pbtnClicked address of method in the subscriber class
    

    I tried right clicking on the first connect and selecting "Find References to Symbol Under Cursor"

    This brought up 4 connects all in qobject.h, I've tried creating a prototype using each of these and none of those worked.

    Can anyone help me to translate these into a prototypes?

    The aim is to wrap up the connection in a class method and then manage the return from the connect so it can be used in a disconnect method.


  • Qt Champions 2017

    So you basically want to have a connect delegate to track the connections? That's pretty trivial actually, something along these lines:

    class SomeClass
    {
        QVector<QMetaObject::Connection> connections;
    
        template <typename Sender, typename Signal, typename Lambda>
        void connect(Sender sender, Signal signal, Lambda lambda)
        {
            QMetaObject::Connection connection = QObject::connect(sender, signal, lambda);
            if (connection)
                connections.append(connection);
        }
    };
    

  • Lifetime Qt Champion

    Hi
    Im not really sure why you want to add such class since you can do

    QMetaObject::Connection m_connection;
    
    m_connection = QObject::connect( /* … */ );
    
    QObject::disconnect( m_connection );
    

    Also, by prototypes you mean each types needed to transfer the Types member method pointer to the other two classes ?

    The connect looks liek this to make it generic

     template <typename Func1, typename Func2>
        static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::type
                connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,
                        Qt::ConnectionType type = Qt::AutoConnection)
    

    But you dont mean templates but concrete actual types ?



  • I have a lot of signals and slots to manage, I'm trying to simplify the code since there are a couple of ways of making a connection. I want a simple way to manage the connections without having to do them individually, wrapping them up in a class makes it easier for me to manage.


  • Qt Champions 2017

    Walk us backwards, how do you want to use the connect. Forget for a second how to do it, say how you want it to look in your code. Here I've fiddled with the connects to "rework" them in a way that was convenient for my purposes, but again it really would depend on what exactly you want to achieve.



  • Ok, presently I have a single function which has a switch case in it to connect all the various signals, there are two types of connect supported by my application, those that allow signals to be connected to JavaScript slots and those that connect to slots in C++.

    I want to replace the switch case with a pointer that will point to an instance of a class that will manage the connection and disconnection of the signals and slots.


  • Qt Champions 2017

    That's not what I asked. Let me give you an example of "asking the right question". When I was about to write the monstrosity sourced above, my line of thought was like this:

    1. I want something that's representing the computational node
    2. I want to have the messages come out of the computational node into the user code (as a natural representation this begs for signals)
    3. I need a way to subscribe to the message from the node
      3.1) Since my node is QObject, I can use connect directly but that's clunky (immediately scrapped)
      3.2) Okay I need something like connect but simpler. Because I know that the sender of the signal is the same always, and the actual signal is the same, I want bind. It should work like this:
    node->bind(receiver, &Class::method);
    node->bind(receiver, [] () -> void {});
    

    And then a decision was made - not how to do it, but what the result of doing it should be; that is I fixed the API.
    3.3) More considerations went into how to make the API more useable
    4) Started coding

    So now back to your question. You're saying how you have it now, that's fine if I had the code and we were discussing the technical details. What I asked was, however how do you expect your code to look. I can't judge by the way it looks now, and I for sure don't know what those pointers are (what they represent). My point was for you to provide a couple of lines of pseudocode of how you imagine that new feature to be working. Is it something like (semi-random):

    MyWrapper wrapper;
    wrapper(someobject).doStuff(&Class::member);
    

    This is what I meant, so we can at least judge what's expected.



  • Ok, I am look to replace the existing code with something simpler, instead of:

        cnSignal = QObject::connect(this
                                   ,&clsQtPushBtn::clicked
                                   ,[pobjScriptEng, strCall, strFile, strScript]() {
                                       QString strScriptWithCall = static_cast<QString>(strScript)
                                                                 + static_cast<QString>(strCall) + "();";
                                       pobjScriptEng->evaluate(strScriptWithCall);
                                });
    

    I would have something like:

        pobjSignal->connect(this
                           ,&clsQtPushBtn::clicked
                           ,[pobjScriptEng, strCall, strFile, strScript]() {
                                QString strScriptWithCall = static_cast<QString>(strScript)
                                                          + static_cast<QString>(strCall) + "();";
                                pobjScriptEng->evaluate(strScriptWithCall);
                            });
    

    pobjSignal would then handle the disconnection automatically. However my original thoughts on why I needed this have gone. I can of course do it in an alternative way, just by using the return from connect.


  • Qt Champions 2017

    So you basically want to have a connect delegate to track the connections? That's pretty trivial actually, something along these lines:

    class SomeClass
    {
        QVector<QMetaObject::Connection> connections;
    
        template <typename Sender, typename Signal, typename Lambda>
        void connect(Sender sender, Signal signal, Lambda lambda)
        {
            QMetaObject::Connection connection = QObject::connect(sender, signal, lambda);
            if (connection)
                connections.append(connection);
        }
    };
    


  • That looks like exactly what I'm after, I have to read up more on Lambda later, have 0 experience with it atm.


  • Qt Champions 2017

    @SPlatten said in Help with connect prototypes.:

    That looks like exactly what I'm after, I have to read up more on Lambda later, have 0 experience with it atm.

    These are simply generic types, so they mean nothing here. The compiler substitutes them with whatever you give it. Just template (black) magic.



  • I know its been a while, I'm revisiting this part of my code and want to simplify it, what I'm after is a way to build up a map of signals and subscribers.

    Presently I have such a map but I want to include the signal functions in with the map.

    The first part of the map is the signal source and name, e.g:

    button_clicked
    checkbox_stateChanged
    

    The second part of the map is a list of objects. Each object in the list is a subscriber to that signal that needs to be notified when the signal is emitted.

    I'm looking for a way to store the signal function as a member, this isn't as simple as I first though because the prototypes for signals differ according to the each function prototype.

    I know that the connect functions provide a means of passing the address of the signal, I can't quite see how to replicate this.


  • Lifetime Qt Champion

    @SPlatten May I ask why you need such a map?
    If an object needs to be notified then connect it to the signal.



  • @jsulm , its part of my project design where everything is configurable and the user can dynamically configure connections between signals and slots (subscribers) at runtime. For this reason I and trying to condense the handling of the slots to something more intelligent.


Log in to reply