Function with Signals & Slots



  • Hi,

    I have the following code:

    connect (Image_Button,SIGNAL(clicked(bool)),this,SLOT(findimage(bool)));
    
           qDebug() <<"The image path is (in main): " << fileName;
    
    QString Additem::findimage(bool)
    {
        qDebug()    << "Find image signal works!";
        Image_Button->setStyleSheet ("QPushButton{"
                                     "background-color:rgb(76, 255, 190);"
                                     "border-style: outset;"
                                     "border-width: 2px;"
                                     "border-radius: 10px;"
                                     "border-color: beige;"
                                     "font: bold 14px;"
                                     "min-width: 10em;"
                                     "padding: 6px;}"
    
                                     );
    
    
        QString sPath = "C:/";
    
        QFileDialog *fileDialog = new QFileDialog;
    
        fileName = fileDialog->getOpenFileName(this,
            tr("Finding Friend's Image"),sPath, tr("Image Files (*.png *.jpg *.bmp)"));
    
    	qDebug() << "(findimage) The image path is " << fileName;
    
        return(fileName);
    

    How can I use the returned function value (fileName) in the line following the

    connect (Image_Button,SIGNAL(clicked(bool)),this,SLOT(findimage(bool)));
    

    line?
    Thank you for your help.


  • Qt Champions 2016

    hi
    You connect directly the button clicked to the slot findimage
    so there is no way to return anything to the button. (the caller)

    You should let the slot call findimage, not be the slot.

    so
    connect (Image_Button,SIGNAL(clicked(bool)),this,SLOT(SetMyStyle(bool)));

    void GetImage::SetMyStyle(bool) {
    QString img=findimage(false);
    .... rest of code
    }



  • You could do as the above comment says, or you could just use the new signal and slot syntax and use a lambda as the "slot". In the lambda you could just call that function and store the results, or use them with something else. For instance:

    connect(imageButton, &QPushButton::clicked, [this]() { imagePath = findImage(); });
    

    If it's something simple as the code above, I prefer to just use lambdas. Either way, I really prefer the newer syntax anyways.


  • Moderators

    @gabor53 You should read again about Qt signals/slots. They are used for asynchronous communication and to react on user interactions. That means if you connect the clicked() signal of a button to a slot that slot will be called when user presses the button. You cannot know when it will happen (for sure not just after connect(...))! So, your current approach does not make any sense.
    You could use another signal and pass the path to the image file as parameter. Then connect a slot to this signal and do what ever you need to do with the image. Or you do everything in findimage().



  • Hi , try this , I think it will handle what you want , use either the A) or B) lines of code depending on your need.

    Qstring m_fileName; // A) in the header for the class

    // inside function
    Qstring tempFileName; // B) at top of function containing following line
    tempFileName =findimage(bool); // A) use this if you don't care about the filename after the function is completed
    m_fileName=findimage(bool);// B) use this if you want the filename global (and possibly used by other classes)
    tempFileName =connect (Image_Button,SIGNAL(clicked(bool)),this,SLOT( m_fileName)); // or B) tempFileName
    // now use the values m_fileName or tempFileName // the m_fileName is global and can be used in other class functions



  • Actually I should say it is global to the other class functions , a member variable to be precise, which as class scope, as opposed to a variable that has File scope. Bear with me, I am just going back to c++ and I have to jog my memory a bit...


  • Moderators

    @Lineaxe What is this?

    tempFileName =connect (Image_Button,SIGNAL(clicked(bool)),this,SLOT( m_fileName));
    

    connect(...) does not call the slot, it returns a bool signalling whether signal was connected to the slot or not. So your code will not even compile.


  • Moderators

    @Lineaxe And you cannot connect a signal to a variable! You can only connect a signal to a slot.



  • right , I should have taken the tempFileName= out , it isn't even needed ...Hmm , looking over a code a bit closer

    QString Additem::findimage(bool)

    return(fileName);

    connect (Image_Button,SIGNAL(clicked(bool)),this,SLOT(findimage(bool)));

    It looks like findimage returns a filename , not a SLOT , so this code would not work. I guess the only way that it could potentially work is if it had a list of slotnames in the QString and it returned them to connect. ( I am really just getting to know the QT environment, as well) . I must say I do like the concept of signals and slots vs events & triggers.



  • Now in his original code for the slot he is using (findimage(bool)) , in the function code he can sure fileName is declared either public or private in the class's header ( m_fileName for example ) so that all the Additem's other class functions will have access to it. Get and Set accessor functions are commonly used with class variables (for many reasons I have discovered) .

    QString Additem::findimage(bool)
    m_fileName = fileDialog->getOpenFileName(this,
    tr("Finding Friend's Image"),sPath, tr("Image Files (*.png *.jpg *.bmp)"));

    return m_fileName;


  • Moderators

    The thing is:

    connect (Image_Button,SIGNAL(clicked(bool)),this,SLOT(findimage(bool)));
    qDebug() <<"The image path is (in main): " << fileName;
    
    • it doesn't matter where fileName (or m_fileName) is declared, after the connect(...) call it will not be set yet because the findimage(bool) slot was not yet called. It will be called when the user clicks on the button - and you never know when the user will click the button.


  • Thank you all. Now I understand what's wrong. After the user clicks Image_Button, I want to display the image in a grid layout in which the Image_Button is. Is there a way I can go back to the grid layout AFTER the user clicked Image_Button and insert the choosen image next to the button?


  • Qt Champions 2016

    Hi if u use @JordanHarris smart version,
    you could do something like
    connect(imageButton, &QPushButton::clicked, this {
    imagePath = findImage();
    QPixmap pic(imagePath);
    ui->SomeQLabel->setPixmap(pic);
    });

    you must insert the "SomeQLabel" into the layout. (just a normal Qlabel)



  • @mrjj ,
    I implemented

    connect(Image_Button, &QPushButton::clicked, [this]() { imagePath = findimage(); })
    

    and I got the following error message:
    C:\Programming\backup\Folkfriends\additem.cpp:195: error: no match for 'operator=' (operand types are 'QString' and 'void')
    connect(Image_Button, &QPushButton::clicked, this { imagePath = findimage(); });
    ^
    I'm wondering what am I missing.


  • Qt Champions 2016

    well basically it says you are doing
    void = QString
    so check that findimage returns Qstring and that
    imagePath is also declared Qstring



  • @mrjj
    I did that. Now it says
    C:\Programming\backup\Folkfriends\additem.cpp:195: error: expected primary-expression before ')' token
    connect(Image_Button, &QPushButton::clicked, this { imagePath = findimage(QString); });
    ^


  • Qt Champions 2016

    Does ur compiler support lambdas?
    Try with empty { }

    connect(Image_Button, &QPushButton::clicked, [this]() {  })
    

    you need Qt 5.5 and newer compiler.



  • @mrjj
    How can I find out if it supports lambdas?


  • Qt Champions 2016

    @gabor53
    well it can then compile the line.
    what compiler is it ?
    VS or mingw?
    and what version?



  • @mrjj
    I have mingw 4.9.2 32 bit


  • Qt Champions 2016

    @gabor53
    ahh, u might need
    CONFIG+=c++11
    in your .pro file for it to use c++ 11 :)



  • @mrjj
    I have that too, so I guess it supports lambdas.


  • Qt Champions 2016

    @gabor53
    It's not the lambda.

    imagePath = findimage(QString);

    This doesn't make sense neither to the compiler nor to me, so you should fix it. What argument are you trying to use findimage with? Currently it has none, and instead of an argument a type name is provided.

    Kind regards.


  • Qt Champions 2016

    @kshegunov
    ahh good spotted. thats the void = QString :)
    I completely missed that .)


  • Qt Champions 2016

    @mrjj
    I just read the compiler errors, it says it right there:

    expected primary-expression before ')' token

    ;)


  • Qt Champions 2016

    @kshegunov
    yeah it's a meaningful and good compiler error :)



  • Heheh, of course that's right. I gotta get back to programming again, I been installing , upgrading and reading too much...
    ** it doesn't matter where fileName (or m_fileName) is declared, after the connect(...) call it will not be set yet because the findimage(bool) slot was not yet called. It will be called when the user clicks on the button - and you never know when the user will click the button. **



  • I changed the following line:

           connect(Image_Button, &QPushButton::clicked, [this]() { imagePath =  findimage( QString);});
    
    to 
    
       connect(Image_Button, &QPushButton::clicked, [this]() { imagePath =  findimage( fileName);});
    
    Now I get the following error message:
    C:\Programming\backup\Folkfriends\additem.cpp:195: error: no match for 'operator=' (operand types are 'QString' and 'void')
            connect(Image_Button, &QPushButton::clicked, [this]() { imagePath =  findimage( fileName);});
                                                        
    What else to change? Thank you.

  • Qt Champions 2016

    Hi
    in the first post you show it as
    findimage(bool)

    so that would be callable as
    imagePath = findimage( true);

    So what you give it as parameter, depends on how u declare it.
    (in the .h file)



  • @mrjj
    I changed it from findimage(bool) to findimage(fileName) because I need it to return the fileName.
    In the .h file it is defined as void findimage(QString fileName);
    I still have the same error message. Thank you.


  • Qt Champions 2016

    @gabor53 said:
    hi
    I would kinda expect it to be declared as
    void findimage();
    as you
    return(fileName);
    in the function and return filename that way.
    so why you need a QString as parameter too ?



  • @mrjj
    I changed it as you recommended:
    in the .h file: void findimage();

     connect(Image_Button, &QPushButton::clicked, [this]() { imagePath =  findimage();});
    
    the function : void Additem::findimage();
    It still gives the same exact error message. Thnks.
    
    

  • Qt Champions 2016

    @gabor53
    void means "nothing", so you're trying to save that "nothing" into a variable, how should that happen? The compiler doesn't know, I don't and I'm pretty sure no one does. If you want to assign a value returned from a function to a variable, well then, by all means, make the function return the proper type and value. Meaning, if you want the function to return a QString then you declare it as such:

    class MyClass
    {
        QString myFunction(); //< MyClass::myFunction is going to return a value of type QString.
    }
    
    QString MyClass::myFunction()
    {
        return QString("Some string"); //< The function returns the value and it is of type QString
    }
    

  • Qt Champions 2016

    sorry my bad
    void findimage();

    should have been

    QString findimage();

    I think i should let @kshegunov handle this one as I keep missing the errors :)



  • @mrjj
    I changed the .h file declaration to QString findimage();.
    Now it works without error, but I still can't capture the findimage returned value (fileName) in the line after connect.
    code
    The function works because the qDebug in the last line returns the correct value.
    How can I return the value before the add layout section so I would be able to display the image next to the button? (That was the original issue I had).

    Thank you.


  • Qt Champions 2016

    @mrjj
    As I noted before, the errors are swiftly and cleanly reported by the compiler:

    C:\Programming\backup\Folkfriends\additem.cpp:195: error: no match for 'operator=' (operand types are 'QString' and 'void')
    connect(Image_Button, &QPushButton::clicked, this { imagePath = findimage( fileName);});

    So the compiler can't make heads or tails of what to do with the arguments given to the assignment operator. :)


  • Qt Champions 2016

    @gabor53

    http://forum.qt.io/topic/64635/function-with-signals-slots/12

    @jsulm already gave you what the problem with this construct is. You're trying to predict the future. You want at some point when the user clicks a button to take an image, and that's fine. The erroneous part is when you want to go back in the past where the connect was made and do something with that image, it's simply not possible. If you want to operate on the value returned from your function, then you should put the code that uses it inside the lambda function, so you wouldn't need to jump through time-travel hoops to get the string. QObject::connect simply says that some function should be called when a signal is emitted, it doesn't guarantee you in any way when or if that shall happen.

    Kind regards.



  • Thank you all. It worked.


Log in to reply
 

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