PDA

View Full Version : qtimer and signal



valgaba
25th November 2011, 16:07
Stream::Stream(QWidget *parent) :
QObject(parent)
{

Timer = new QTimer();
connect(Timer, SIGNAL(timeout()), this, SLOT(Update()));
Timer->start(30);
}



void Stream::Update(){
ActualizarContadores();

if (IsFinal(streamUltimo)){
Timer->stop();
if(!Timer->isActive ()){

emit Finish();

}

}

}


Depending on OS and Hardware Finish signal () is issued more than once, ie on windows vista once it is issued is the idea of ​​2 or more consecutive xp.
Is there a mechanism to ensure that the signal is issued only once?

thanks

Spitfire
25th November 2011, 17:04
It's probably because of whatever happens in the Update() before Timer->stop() takes longer than 30ms and timer fires again while Update is being processed.
Try this:
void Stream::Update()
{
ActualizarContadores();

if ( IsFinal( streamUltimo ) )
{
if( Timer->isActive() )
{
Timer->stop();
emit Finish();
}
}
} Now finish should be emitted only once, but there's no guarantee that the timer won't fire again because of how long it takes to Update().

Btw the check you make in line #17 doesn't make any sense as it's always true.

d_stranz
25th November 2011, 23:46
If you only need the timer to fire once, then use this in the constructor:



Stream::Stream(QWidget *parent) : QObject(parent)
{
QTimer::singleShot( 30, this, SLOT( Update() ) );
}


No need to create a QTimer instance if you don't intend to reuse it. Your slot then becomes simply:



void Stream::Update()
{
ActualizarContadores();

if ( IsFinal( streamUltimo ) )
{
emit Finish();
}
}

stampede
26th November 2011, 00:39
I think OP meant that finished() signal is fired more than once after the "final" processing.
You can use boolean variable the control it:


Stream::Stream(QWidget *parent) :
QObject(parent)
{

Timer = new QTimer();
connect(Timer, SIGNAL(timeout()), this, SLOT(Update()));
Timer->start(30);
this->isFinished = false; // declared as bool member
}

void Stream::Update(){
if( this->isFinished )
return;

ActualizarContadores();

if ( IsFinal( streamUltimo ) )
{
this->isFinished = true;
if( Timer->isActive() )
{
Timer->stop();
emit Finish();
}
}

}

Since everything happens in one thread, you can be sure that Finish() will be emitted once in this case.

d_stranz
26th November 2011, 20:06
I think OP meant that finished() signal is fired more than once after the "final" processing.


Right, and I think Spitfire was correct in ascertaining why - the timer fires again before the first processing finishes, so the slot is entered again. In your code, I don't think the Boolean flag adds anything that stopping the timer doesn't already do, except to prevent the other functions from being called more than once. Once the timer has been stopped first time through the slot, the Finished signal won't be fired again because isActive() will be false. Your flag actually will prevent the GUI from being updated ("ActualizarContadores").

I assumed that the OP wanted to simply wait 30 ms before the slot gets called. If in fact he wanted to continuously update the GUI until IsFinal() returns true, then Spitfire's code will do this and also ensures that the Finished() signal get emitted exactly once unless something elsewhere restarts the timer.

It's hard to know what the OP's actual intent is, with just fragments of code.