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

When passing a signal to a slot function,can I carry my own defined parameters?



  • My application has 100 buttons,each button corresponds to a string,after pressing a button,the corresponding string will be output,I only want to use one slot function to complete this work;the principle I imagined is very simple:these 100 buttons are an array,when the connection between the signal and slot is initialized,the array subscript of button is also passed directly,but the code I wrote can't complete this work,as shown below show:

     for(int i=0; i<100; i++)
        {
            layout->addWidget(&pushButton[ i ]);
            connect(&pushButton[ i ],SIGNAL(clicked( int i )),  this,SLOT(slotClicked( int )));
        }
    

    Obviously,in “connect”,the working method of “SIGNAL” is not what I imagined;so I would like to ask here:When the signal is connected to the slot,can I send my own custom parameter?just like this application,when the user clicks a button,can there be an extra “int” parameter in the signal send?this “int” parameter is the subscript corresponding to button that the user clicks in button array。



  • @Poor-English
    Well, although I know it would work for your situation, I actually suggested you do not use QSignalMapper! That is good only for a certain limited class of cases where you want to pass a parameter from signal to slot. And once you are comfortable with lambdas you can do much more with them.

    All you should need for your example is:

    for(int i = 0; i < 100; i++)
    {
        layout->addWidget(&pushButton[i]);
        connect(&pushButton[i], &QPushButton::clicked,
                this, [this, i]() { this->slotClicked(i); });
    }
    
    

    The magic in the [this, i] is that it passes those variables from where the connect() is called into the body of the lambda where we need to use them in this->slotClicked(i);.



  • @Poor-English
    Yes: You are going to need to read up and learn C++ lambdas to do this.

    And please change over to https://wiki.qt.io/New_Signal_Slot_Syntax.

    That topic shows what you need to do, and shows lambda example ("Can be used with C++11 lambda expressions"). And another example in https://doc.qt.io/qt-5/signalsandslots.html#advanced-signals-and-slots-usage.

    You could also do this particular one with QSignalMapper, or even with QObject::sender(). But I wouldn't recommend either: once you have got the hang of lambda slots with extra parameters they are much more flexible and you will use them elsewhere.



  • Dear Mr.cat,I am glad to see your guidance again,since I have been helping the uncle's house to carry he's pears yesterday,I have not responded to your enthusiasm in time,sorry!
    Thank you for these two links,although I know they are all in English,but I will bite the bullet and click into learn;also thank the great Google and Goolgle translate



  • @JonB
    Thank you for your enlightenment!I have used the QSignalMapper you suggested to solve the problem!but there is still a small dark cloud hidden in my heart,I wanted to use lambda at first,but no matter what posture I use, it doesn't can do it!The crux appears here:just like the for loop in my question,the ”i“ is just a local variable,so how can my lambda function capture her?



  • @Poor-English
    Well, although I know it would work for your situation, I actually suggested you do not use QSignalMapper! That is good only for a certain limited class of cases where you want to pass a parameter from signal to slot. And once you are comfortable with lambdas you can do much more with them.

    All you should need for your example is:

    for(int i = 0; i < 100; i++)
    {
        layout->addWidget(&pushButton[i]);
        connect(&pushButton[i], &QPushButton::clicked,
                this, [this, i]() { this->slotClicked(i); });
    }
    
    

    The magic in the [this, i] is that it passes those variables from where the connect() is called into the body of the lambda where we need to use them in this->slotClicked(i);.



  • @JonB

                _btn[i][j].setFont(font);
    
    //            connect(&_btn[i][j],&QPushButton::clicked,
    //                [&](){
    //                _btn[9][9].setText(_turn ? "O" : "X");
    //                _turn = !_turn;
    //            });
    
                connect(&_btn[i][j],&QPushButton::clicked,
                    [&,i,j](){
                    _btn[i][j].setStyleSheet(_turn ? "color:red" : "color:black");
                    _btn[i][j].setText(_turn ? "O" : "X");
                    _turn = !_turn;
                });
    
    //            connect(&_btn[i][j],SIGNAL(clicked()), btnMapper,SLOT(map()));
    //            btnMapper->setMapping(&_btn[i][j], i*15+j);
            }
     //   connect(btnMapper,SIGNAL(mapped(int)), SLOT(slotClickBoard(int)));
    

    Perfect!!you not only helped me solve the problem,but also let me learn the beauty of lambda!I only came into contact with lambda from cocos2d,and thought she only has three forms:【&】、【=】and【 】,I didn't expect that she could capture local variableds directly!
    It is difficult to express my gratitude to you in a thousand words!I think for you,my only strength should be my understanding for China and Chinese proficiency,so if you are curious or interested in certain things in China,you can just ignore the problem,such as the cooking steps of food



  • @Poor-English
    [=] & [&] are "special" so I thought I wouldn't cover them. I tend not to use them anyway (you usually don't need to in almost any situation). But let's go through this context specifier for lambdas:

    • []: pass no variables from method to lambda.

    • [=]: pass all local variables by value from method to lambda. Includes this.

    • [&]: pass all local variables by reference from method to lambda. Includes this.

    But we don't need to use [=] or [&]. We can pass the necessary variables explicitly instead, as we please: [this, i, &j, k, &l]. Which personally I prefer.


Log in to reply