PDA

View Full Version : Beginner trying to iterate through image list, counter getting corrupted



Jon Heron
11th October 2010, 03:16
Hello all,

I am a beginner learning Qt C++.
I am making an application for Symbian that will teach the user how to tie knots. I am intending to iterate through a list of images and text strings to display them to the user via 2 QLabels. I would like to give the user an option to "play" or iterate automatically with an adjustable delay.
The problem is whenever I stop play and then start again my counter (in changeImage() )gets screwed up and the the order of the images gets all messed up. :(
PushButton_3 is the play pause button that calls the timer which calls the change image routine.
I cant figure out where the counter is getting screwed up with this simple code... I am sure this is some basic mistake I am making like usual... :o

Header for the knot view dialog;

#ifndef KNOTVIEWDLG_H
#define KNOTVIEWDLG_H

#include <QDialog>
#include "whatknot.h"
#include <QObject>
#include <QTimer>

namespace Ui {
class knotViewDlg;
}

class knotViewDlg : public QDialog
{
Q_OBJECT

public:
explicit knotViewDlg(QWidget *parent = 0);
~knotViewDlg();
void keyPressEvent(QKeyEvent *);
//current image name vari
QString cntKnot;
//Current list of image names
QStringList strLst;
int counter; // image list counter
int delay; //image delay
bool play; // is playing?
// Timer
QTimer* timer;
private:
Ui::knotViewDlg *ui;
public slots:
void getIndex(QString knot);
void timing();
void changeImage();

private slots:
void on_pushButton_3_clicked();
};
#endif // KNOTVIEWDLG_H


And here is the cpp;

#include "knotviewdlg.h"
#include "ui_knotviewdlg.h"
#include "ui_whatknot.h"
#include "whatknot.h"
#include <QStringList>
#include <QDir>
#include <QDebug>
#include <QKeyEvent>

knotViewDlg::knotViewDlg(QWidget *parent) :
QDialog(parent),
ui(new Ui::knotViewDlg)
{
ui->setupUi(this);
//init timer
timer = new QTimer(this);
play = false;
delay = 1000; //image play delay default 1s

QStringList result;
//setup d with the path to the resource images
QDir d(":/knotImages/images");
//populate result with all image names
result = d.entryList();
//search result for key word
QString str1 = cntKnot; //set str1 with selected knot name
QString str;
strLst = result.filter(str1);
//set first image before calling timer
str = strLst.at(0);
ui->label->setPixmap(QPixmap(QString::fromUtf8(
":/knotImages/images/").append(str)));
}

knotViewDlg::~knotViewDlg()
{
delete ui;
}

void knotViewDlg::getIndex(QString knot)
{
const QString cntKnot = knot;
}
void knotViewDlg::changeImage()
{
QString str = strLst.at(counter);
ui->label->setPixmap(QPixmap(QString::fromUtf8(
":/knotImages/images/").append(str)));
counter++;
if(counter >= (strLst.count()))
{
counter = 0;
}

}

void knotViewDlg::timing()
{
//default delay between images 1s
timer->setInterval(delay);
connect(timer, SIGNAL(timeout()),SLOT(changeImage()));
timer->start();
}

void knotViewDlg::on_pushButton_3_clicked()
{
if(play == false)
{
play = true;
timing();
}
else
{
timer->stop();
play = false;
}

}

Any and all advice is greatly appreciated!
Cheers,
Jon

tbscope
11th October 2010, 04:37
void knotViewDlg::on_pushButton_3_clicked()
{
if(play == false)
{
play = true;
counter = 0; // Do not forget to reset the counter
timing();
}
}

Jon Heron
11th October 2010, 04:50
Thanks!
That will certainly work to reset the images from the start each time. However, I would like to be able to pause the iteration, not reset it with the pushButton.
Something very strange is going on with the int counter variable after the iteration is paused. Once its started again the order of the images is completely messed up, it seems random too. Once and awhile after a pause and restart it will play the same 2 images over and over... I dont see how thats even possible with the code above... Its like something is messing up the order on the strLst?

Cheers,
Jon

gboelter
11th October 2010, 05:09
Hi Jon,

your code is a little bit unique. I will give you a sample:

Instead ...


void knotViewDlg::changeImage()
{
QString str = strLst.at(counter);
ui->label->setPixmap(QPixmap(QString::fromUtf8(
":/knotImages/images/").append(str)));
counter++;
if(counter >= (strLst.count()))
{
counter = 0;
}

}


try it like this for example ...



void knotViewDlg::changeImage()
{
label->setPixmap( QPixmap(QString::fromUtf8( strLst.at( counter ) ) ) );

++counter;
if( counter >= ( strLst.count() ) )
counter = 0;
}


And then add something like


//for debugging only ...
qDebug() << "current counter is:" << counter;
qDebug() << "current image is:" << strLst.at( counter );

Regards
Guenther

Jon Heron
11th October 2010, 06:01
Thanks Guenther!
Your debug output suggestion showed me that the order of the counter and strLst was correct, the signal to changeImage() was still getting called after timer->stop() was called. A simple edition of timer->disconnect(); did the trick!

void knotViewDlg::on_pushButton_3_clicked()
{
if(play == false)
{
play = true;
timing();
}
else
{
timer->stop();
timer->disconnect(); //needed to stop signals
play = false;
}

}

Cheers,
Jon

ChrisW67
11th October 2010, 06:57
Each time timing() was called (i.e. when the button was pressed) you connect the timer's timeout() signal to your changeImage() slot again. Duplicate connections lead to duplicate signals. Connect the timer and slot once in the constructor and use the push button slot to toggle the timer start()/stop() (and adjust timer period if needed).

Jon Heron
11th October 2010, 14:25
Ahhhh! I get it!
That makes perfect sense! :o
Thanks Chris!
Cheers,
Jon