Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Custom signal to slot : The slot requires more arguments than the signal provides.
QtWS25 Last Chance

Custom signal to slot : The slot requires more arguments than the signal provides.

Scheduled Pinned Locked Moved Solved General and Desktop
signals slotslambda
15 Posts 4 Posters 6.1k 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.
  • Petross404_Petros SP Offline
    Petross404_Petros SP Offline
    Petross404_Petros S
    wrote on last edited by Petross404_Petros S
    #1

    I want to emit a custom signal void qmovieFrameChanged() when void QMovie::frameChanged(int frameNumber) is emitted, so it can
    execute the following :

    void QtDice::stop_last_frame(QMovie* movie)
    {
          if( movie->currentFrameNumber() == (movie->frameCount() -1))
    	{
    		movie->stop();
    		if(movie->state() == QMovie::NotRunning)
    		{
    			emit movie->finished();
    		}
    	}
    }
    

    So :

    //What I want: 
    connect(movie, &QMovie::frameChanged, this, &QtDice::qmovieFrameChanged);
    connect(this, &QtDice::qmovieFrameChanged, this, &QtDice::stop_last_frame);
    //What I get : The slot requires more arguments than the signal provides.
    

    The error makes totally sense but I need a way to call this function when QMovie::frameChanged is emitted without a lambda.

    Declaring the signal as void qmovieFrameChanged(QMovie*) doesn't help either.

    I understand that QMovie::frameChanged(int frameNumber) requires the signal to accept an int but I can't test movie's frameCount etc inside the stop_last_frame if I make it accept integer.

    I need to pass the object movie in order to call it's methods and do what I have to do. Is there something I am missing here and/or can I overcome compiler's denial?

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      Why not make movie a class member ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      Petross404_Petros SP 1 Reply Last reply
      2
      • mrjjM Offline
        mrjjM Offline
        mrjj
        Lifetime Qt Champion
        wrote on last edited by
        #3

        Hi
        Adding to @SGaist, are u sharing a (one) QMovie with multiple QtDices ?
        or how come its dont belong to QtDice?

        You can subclass QMovie and add such new signal but its odd design to have a class emit a "this" pointer (IMHO).

        1 Reply Last reply
        3
        • SGaistS SGaist

          Hi,

          Why not make movie a class member ?

          Petross404_Petros SP Offline
          Petross404_Petros SP Offline
          Petross404_Petros S
          wrote on last edited by Petross404_Petros S
          #4

          @SGaist Like this?

          ...
          private:
              QMovie* movie;
          ...
          

          I don't know if I am correct here, but it reminded me of global variables. I created (and destroyed) the QMovie object inside the function that needed it; not in the constructor for example.

          The only objects that are visible everywhere in my program are those (widgets) that I created with Designer. So, the label that shows the movie is included from qtdice.h (actually from ui_qtdice.h), but for some reason I felt like it's wrong to fill my header with private objects all over the place.

          Correct me if I am wrong. :-)

          @ mrjj
          No, there is only one QtDice which calls void QtDice::image_update(int image_number) which in turn creates in scope a QMovie.

          But please, elaborate on this :

          You can subclass QMovie and add such new signal but its odd design to have a class emit a "this" pointer

          I suppose you mean I can create a custom QMovie class that will inherit from the original one and will add my functionality. So there will be no need to emit custom signals to custom slots...? It's quite convenient, like when you want to press a button and call some function you need.

          connect(m_ui->m_button, &QPushButton::clicked,
                      this, static_cast<void (QtDice::*)(void)>(&QtDice::reload));
          //The whole cast thing is because reload is overloaded
          
          mrjjM 1 Reply Last reply
          0
          • Petross404_Petros SP Petross404_Petros S

            @SGaist Like this?

            ...
            private:
                QMovie* movie;
            ...
            

            I don't know if I am correct here, but it reminded me of global variables. I created (and destroyed) the QMovie object inside the function that needed it; not in the constructor for example.

            The only objects that are visible everywhere in my program are those (widgets) that I created with Designer. So, the label that shows the movie is included from qtdice.h (actually from ui_qtdice.h), but for some reason I felt like it's wrong to fill my header with private objects all over the place.

            Correct me if I am wrong. :-)

            @ mrjj
            No, there is only one QtDice which calls void QtDice::image_update(int image_number) which in turn creates in scope a QMovie.

            But please, elaborate on this :

            You can subclass QMovie and add such new signal but its odd design to have a class emit a "this" pointer

            I suppose you mean I can create a custom QMovie class that will inherit from the original one and will add my functionality. So there will be no need to emit custom signals to custom slots...? It's quite convenient, like when you want to press a button and call some function you need.

            connect(m_ui->m_button, &QPushButton::clicked,
                        this, static_cast<void (QtDice::*)(void)>(&QtDice::reload));
            //The whole cast thing is because reload is overloaded
            
            mrjjM Offline
            mrjjM Offline
            mrjj
            Lifetime Qt Champion
            wrote on last edited by
            #5

            @Petross404_Petros-S
            Hi
            You would have to hook up the old signal to private slot and
            emit your new signal with the "this" pointer in that slot since you want to change what is
            emitted.

            If dice is using QMovie, it would be fine if it had it as a private member as then
            its very self contained.

            Petross404_Petros SP 1 Reply Last reply
            2
            • mrjjM mrjj

              @Petross404_Petros-S
              Hi
              You would have to hook up the old signal to private slot and
              emit your new signal with the "this" pointer in that slot since you want to change what is
              emitted.

              If dice is using QMovie, it would be fine if it had it as a private member as then
              its very self contained.

              Petross404_Petros SP Offline
              Petross404_Petros SP Offline
              Petross404_Petros S
              wrote on last edited by
              #6

              @mrjj

              Hmm, I haven't thought of the old syntax. Thank you, I will test tomorrow morning and report any findings.

              mrjjM 1 Reply Last reply
              0
              • Petross404_Petros SP Petross404_Petros S

                @mrjj

                Hmm, I haven't thought of the old syntax. Thank you, I will test tomorrow morning and report any findings.

                mrjjM Offline
                mrjjM Offline
                mrjj
                Lifetime Qt Champion
                wrote on last edited by mrjj
                #7

                @Petross404_Petros-S
                Not the old syntax, the old signal frameChanged.
                You would bind it to a private slot and
                void MyMovie::FrameChanged() {
                emit MynewFrameChanged(this);
                }

                But please check if move could just be in Dice as its the main user and
                should just have the object then.

                Petross404_Petros SP 1 Reply Last reply
                0
                • mrjjM mrjj

                  @Petross404_Petros-S
                  Not the old syntax, the old signal frameChanged.
                  You would bind it to a private slot and
                  void MyMovie::FrameChanged() {
                  emit MynewFrameChanged(this);
                  }

                  But please check if move could just be in Dice as its the main user and
                  should just have the object then.

                  Petross404_Petros SP Offline
                  Petross404_Petros SP Offline
                  Petross404_Petros S
                  wrote on last edited by
                  #8

                  @mrjj OK before powering off my pc, I thought let's try to declare QMovie* movie as a private member of QtDice.

                  Afterwards, just before using the movie, I setted the filename movie.setfilename(":/images/etc") but the compiler ranted something about static variable movie but I am quite sleepy to remember.

                  Perhaps I must also use new somehow on an existing variable to actually create it. I think I found what I will be looking the next day.

                  All the best, Petros.

                  mrjjM 1 Reply Last reply
                  0
                  • Petross404_Petros SP Petross404_Petros S

                    @mrjj OK before powering off my pc, I thought let's try to declare QMovie* movie as a private member of QtDice.

                    Afterwards, just before using the movie, I setted the filename movie.setfilename(":/images/etc") but the compiler ranted something about static variable movie but I am quite sleepy to remember.

                    Perhaps I must also use new somehow on an existing variable to actually create it. I think I found what I will be looking the next day.

                    All the best, Petros.

                    mrjjM Offline
                    mrjjM Offline
                    mrjj
                    Lifetime Qt Champion
                    wrote on last edited by mrjj
                    #9

                    @Petross404_Petros-S
                    Yes , yes you MUST new it in QtDice constructor before use.
                    (movie = new QMovie(this) )

                    and its
                    movie ->setfilename not the . (dot) syntax :)
                    (-> for pointers DOt is for non pointers)

                    1 Reply Last reply
                    2
                    • Petross404_Petros SP Offline
                      Petross404_Petros SP Offline
                      Petross404_Petros S
                      wrote on last edited by
                      #10

                      Yes , yes you MUST new it in QtDice constructor before use.

                      Actually, when I new it in QtDice::QtDice I get a segfault when I try to set it's filename in the slot void QtDice::image_update(int) .

                      The moment I write in the latter, QMovie movie = new QMovie(this) and afterwards set the filename, it works.

                      Anyway that isn't Qt specific anymore but about my lack of proper C++ understanding. I will keep this for a little longer UNSOLVED and will post any findings to close it. Thank you very much.

                      1 Reply Last reply
                      0
                      • VRoninV Offline
                        VRoninV Offline
                        VRonin
                        wrote on last edited by
                        #11

                        connect(movie, &QMovie::frameChanged, this, std::bind(&QtDice::qmovieFrameChanged,this,movie));

                        "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                        ~Napoleon Bonaparte

                        On a crusade to banish setIndexWidget() from the holy land of Qt

                        1 Reply Last reply
                        3
                        • mrjjM Offline
                          mrjjM Offline
                          mrjj
                          Lifetime Qt Champion
                          wrote on last edited by
                          #12

                          hi
                          My guess is that u do the classic error/facepalm
                          QMovie movie = new QMovie(this) ; // this make a LOCAL variable. not what u want
                          To use the one from .h
                          movie = new QMovie(this); // NOTICE No TYPE FIRST. we set the member to something.

                          1 Reply Last reply
                          3
                          • Petross404_Petros SP Offline
                            Petross404_Petros SP Offline
                            Petross404_Petros S
                            wrote on last edited by Petross404_Petros S
                            #13

                            @VRonin

                            Indeed that worked! Compiler didn't warn about anything and as a matter of fact I was thinking of QSignalMapper and std::bind but thought it would be very complex. It's a chance to take a closer look at your code and practice on toy-programs with bind.

                            Anyway, with your solution I don't need a lambda for this anymore.

                            @mrjj

                            In the ctror I wrote movie = new QMovie(this) but there is another problem. Now that I use a private class member movie, the animation doesn't play. The gif is shown, but it's frozen. It doesn't matter if I use std::bind as VRonin proposed or if I use the lambda.

                            As long as the QMovie is created in the ctor like this :

                            // In the ctor
                            movie = new QMovie(this);
                            movie->setFileName(":/images/rolling_infinite.gif");
                            ...
                            //In void QtDice::image_update(int image_number)
                            ....
                            m_ui->label->setMovie(movie);
                            //Animation works!
                            

                            But I set the movie's filename inside the function :

                            // In the ctor
                            movie = new QMovie(this);
                            ....
                            // In the void QtDice::image_update(int image_number)
                            movie->setFileName(":/images/rolling_infinite.gif");
                            m_ui->label->setMovie(movie);
                            
                            if(movie->isValid())
                            {
                            //again is valid is printed, Qt continues to accept movie as valid.
                            	qDebug() << "is valid" << '\n';
                            	movie->start();
                            }
                            else...
                            //Gif is shown, but doesn't animate
                            

                            I even tried to append this-> infront of movie but of course this wasn't the problem. It can access the variable as there isn't any movie in scope. I can drop the issue here because the custom signal to signal connection is accomplished, but I want to know how to debug the stopped animation problem. GUI isn't unresponsive, I guess it's not a crash...

                            1 Reply Last reply
                            0
                            • mrjjM Offline
                              mrjjM Offline
                              mrjj
                              Lifetime Qt Champion
                              wrote on last edited by mrjj
                              #14

                              Hi
                              it really should work the same as in ctor.
                              Must be something else.
                              In what function is example 2 ?

                              1 Reply Last reply
                              1
                              • Petross404_Petros SP Offline
                                Petross404_Petros SP Offline
                                Petross404_Petros S
                                wrote on last edited by Petross404_Petros S
                                #15

                                @mrjj It goes like this :

                                Ctor connects a pushbutton click with QtDice::reload which in turn calls QtDice::image_update to animate the gif and after it's finished, show an image.

                                I found out what the problem is. QtDice::image_update is called multiple times and therefore it tries to setFileName every time. So a check if fileName() is empty must be done each time before attempting to setFileName.

                                void QtDice::image_update(int image_number)
                                {
                                	//Make sure we don't constantly re-append a fileName!
                                	if(movie->fileName() == "" )
                                	{
                                		movie->setFileName(":/images/rolling_infinite.gif");
                                		
                                		//If it still is empty print error and exit. Not good at all
                                		//TODO wrap the setFileName in some Qt assert to throw an exception
                                		if (movie->fileName() == "")
                                		{
                                			qDebug() << "Error! Couldn't set a fileName to read for the animation";
                                			QApplication::quit();
                                		}
                                	}
                                	
                                	m_ui->label->setMovie(movie);
                                	.....
                                }
                                

                                I don't know exactly why this failed ( I mean I could change the fileName as many times as I like), but I checked and rechecked that with this if (movie->fileName() == "" ).... the animation works.

                                That could also explain why some (but not all) times the animation played the very first time I push the button (ie called the function) and the second time it stopped. If someone thinks that other reasons come into play, please inform me, I am more than glad to learn.

                                For any of you, that is curious what is the code and/or want to c&c, this is the QtDice and this is a screenshot

                                Have a nice afternoon!

                                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