[Solved] How to make a loop run slower with Qt's Classes?



  • Hi everyone!

    I'm trying to make a for loop to run slower, like:
    @
    for ( int i = 0; i < n; ++i)
    {
    }
    @

    Each time i changes, the loop need to wait some miliseconds.

    How can I archive it the smartest/shortest way?

    I tried QTimer but somehow.. I don't know how to use it with the funtion I wrote (Which need to be execute in exactly 1 sec repeatly inside the for loops) . If someone can guide me with using QTimer then it's a big help!

    Lots of thanks for any answer given!


  • Moderators

    You could use "QThread's sleep method":http://qt-project.org/doc/qt-4.8/qthread.html#sleep , but that seems to be beyond what you are trying to achieve.

    With any method it may be hard to achieve exactly 1 seconds intervals.

    You may want to study the "Analog clock example":http://qt-project.org/doc/qt-5.0/widgets-analogclock.html



  • You can include the windows.h header file and use the Sleep(int milliseconds) function, if you are using Windows, of course.



  • Hello.
    I suggest you to invert logic: create a class which has a timer (QTimer) and perform work on timer’s tick. However it’s not the same as using a simple cycle so you may need something like "this":http://qt-project.org/forums/viewreply/39788/



  • Thanks for all your replies.

    Things is, I need to play some media files which have same length (1 sec) one after another.

    The for loop purpose is to change the media's name.

    I have a "playMedia" funtion, which use QMediaPlayer to generate the file path and play the file.

    This is how it looks like for the times being:

    @

    void main::playMedia (QString mediaName, QMediaPlayer *player)
    {
    ...............
    }

    void main::changeMedia()
    {
    QStringList mediaList;
    .............
    for ( i = 0; i < mediaList.size(); ++i){
    playMedia (mediaList.at(i), player);
    }
    }
    @

    Like this, then the for loops won't pause for the media to finish playing the first files, which length is 1 sec.

    If I use QTimer, it seem the timer will affect every playMedia funtion I have, but I also need to use this funtion not within 1 sec.

    Please give me further detail about how to use QTimer in this case, or if you can give me other solution for this problem, then much appreciated.



  • Try the QThread usleep function which causes to sleep your current thread.

    @QThread::usleep(1000000)@


  • Moderators

    Instead of forcing a loop to run at a particular speed, could you emit a Signal every time you finish playing a file? That way, your Slot is called immediately after the file finishes, and you can call playMedia() at the correct time.

    You may need another member variable to keep track of how many files you've played so far.



  • bq. Use sleep.

    You don't want to do that.

    You have to be aware that you don't just delay your loop, but rather suspend your main thread for the given amount of time. This means there is neither an event loop spinning (no user interaction, no signal processing, no background tasks like network transfer) nor (if QMediaPlayer doesn't use a dedicated render thread) any video playback at all. Your application is unresponsive for at least mediaList.size() seconds.

    There is a simple rule of thumb for event-driven applications: if you use sleep (or alike) in the main thread your design is broken, and so your application will be.

    If you want to change to another media file each second create a timer (if you need high precision use Qt5's Qt::PreciseTimer) and connect to its QTimer::timeout() signal. If you just want to change to another media file once the previous has finished connect to the QMediaPlayer::stateChanged signal or use a QMediaPlaylist in the first place.



  • Thanks to all your reply.

    Because after testing this, I will use it with longer files, so QMediaPlaylist isn't a solution.

    I have implemented the code using QTimer inside the for loop.

    The program run, but it said no such signal QMediaPlayer::stateChanged nor QMediaPlayer::mediaChanged whenever I call the playMedia slot.

    Here is what I have so far:

    @
    void main::playMedia (QString mediaName, QMediaPlayer *player)
    {
    ...............
    }

    void main::changeMedia()
    {
    QStringList mediaList;
    QMediaPlayer *player;
    .............
    for ( i = 0; i < mediaList.size(); ++i)
    {
    QTimer *timer = new QTimer(this);
    timer->start (1000);
    connect (timer, SIGNAL (timeout()), player, SIGNAL (QMediaPlayer::stateChanged()));
    playMedia (mediaList.at(i), player);
    }
    }
    @

    BTW, after reading QTimer's doc, I thought that the line:
    @
    connect (timer, SIGNAL (timeout()), player, SIGNAL (QMediaPlayer::stateChanged()));
    @

    will do the QMediaPlayer::stateChanged() once each time timeout() emit. Is that right?

    I have tried QTimer::singleshot() inside the for loop with my playMedia funtion, but it seem I can't pass argument while singleshot's called, here's my code for that:

    @
    QTimer::singleShot (1000, this, SLOT (playMedia(mediaList.at(i), player));
    @

    Please point out what I was wrong/ misconcept/ misunderstanding, thanks.



  • [quote author="A.A.B.A" date="1346057058"]Because after testing this, I will use it with longer files, so QMediaPlaylist isn't a solution.[/quote]Why?

    [quote author="A.A.B.A" date="1346057058"]I have implemented the code using QTimer inside the for loop.[/quote]You will have to create a timer object once, for example in the constructor of your class. Once you QTimer::start() the timeout() signal will be emitted consecutively. Add a slot to your class which takes no arguments but just plays the next media and connect it to the timeout() signal.

    An alternative is connecting this slot to the stateChanged() signal, which is emitted once the current media has stopped playing. You don't need a timer then.


  • Moderators

    [quote author="A.A.B.A" date="1346057058"]The program run, but it said no such signal QMediaPlayer::stateChanged nor QMediaPlayer::mediaChanged whenever I call the playMedia slot.

    ...
    @connect (timer, SIGNAL (timeout()), player, SIGNAL (QMediaPlayer::stateChanged()));@
    [/quote]
    See http://qt-project.org/doc/qt-5.0/qmediaplayer.html -- the signals have parameters which you must follow. stateChanged(QMediaPlayer::State) exists, but stateChanged() doesn't exist.

    [quote author="A.A.B.A" date="1346057058"]BTW, after reading QTimer's doc, I thought that the line:
    @connect (timer, SIGNAL (timeout()), player, SIGNAL (QMediaPlayer::stateChanged()));@
    will do the QMediaPlayer::stateChanged() once each time timeout() emit. Is that right?

    ...

    Please point out what I was wrong/ misconcept/ misunderstanding, thanks.[/quote]Don't use the timer to force QMediaPlayer to emit the stateChanged() signal... that's wrong. QMediaPlayer is supposed to emit the signal by itself, when it's ready.

    Like Lukas said, you should choose one signal:

    Use QTimer::timeout() only, or

    Use QMediaPlayer::stateChanged(QMediaPlayer::State) only

    Don't use both.

    I recommend that you spend some time to read a simple tutorial on Signals & Slots. After you build up your understanding, things will become much easier! I like this one: http://doc.trolltech.com/4.3/tutorial.html ...it starts very simple, but ends with very advanced examples.



  • I have implemented the QTimer to make the playMedia funtion execute as wanted!

    I created the QTimer once the program start, and connect it with the play funtion.

    Thanks everyone!


Log in to reply
 

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