Проблем при показване на последователност от изображения с setPixmap в Qlabel

Опитвам се да покажа последователност от изображения чрез Qlabel, използвайки setPixmap. Имам QStringList, съдържащ имената на файловете с изображения и for цикъл, който итерира през изображенията с 5 секунди изчакване след всяко изображение. Въпреки това само последният файл с изображение се показва. В момента екранът остава празен по време на изчакване на първите итерации, докато най-накрая се покаже последното изображение. Четох, че използването на for цикъл няма да работи и че вместо това трябва да използвам сигнали и слотове. Все пак съм нов в тази концепция и наистина бих се радвал на пример, който да ме насочи в правилната посока.

Ето текущия ми код:

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),ui(new Ui::MainWindow){
   ui->setupUi(this);
   QStringList images;
   QString imageName;
   images << "redScreen.png" << "blueScreen.png" << "greenScreen.png";

   for(int x=0; x < images.size(); x++){
      imageName = images.at(x);
      this->displayScreen(imageName, 5);
   } 
}

void MainWindow::displayScreen(QString imageName, int wait){
   QTimer t;
   QEventLoop loop;
   QPixmap myImage;

   myImage.load(":/images/" + imageName);
   ui->imageLabel->setPixmap(myImage);
   ui->imageLabel->repaint();

   // 5 second wait between next iteration
   t.start(wait*1000);
   connect(&t, SIGNAL(timeout()), &loop, SLOT(quit()));
   loop.exec();
}

person Juliana    schedule 14.07.2014    source източник
comment
Защо използвате QEventLoop в този случай?   -  person DeepBlack    schedule 15.07.2014
comment
Използвам го като забавяне   -  person Juliana    schedule 15.07.2014


Отговори (3)


Хакът за повторно включване в режим на изчакване чрез цикъл на събития е чудесен източник на трудни за диагностициране грешки. Не го използвай. Много, много рядко ще трябва да създадете свой собствен цикъл на събития. Дори доста сложни проекти могат напълно да го избегнат.

Трябва просто да стартирате таймер и да реагирате на отметките на таймера. Ето един пример:

#include <QApplication>
#include <QImage>
#include <QGridLayout>
#include <QLabel>
#include <QBasicTimer>

class Widget : public QWidget {
    QGridLayout m_layout;
    QLabel m_name, m_image;
    QStringList m_images;
    QStringList::const_iterator m_imageIt;
    QBasicTimer m_timer;
    void timerEvent(QTimerEvent * ev) {
        if (ev->timerId() == m_timer.timerId()) tick();
    }
    void tick() {
        display(*m_imageIt);
        m_imageIt ++;
        const bool loop = false;
        if (m_imageIt == m_images.end()) {
            if (loop)
                m_imageIt = m_images.begin();
            else
                m_timer.stop();
        }
    }
    void display(const QString & imageName) {
        QImage img(":/images/" + imageName);
        m_name.setText(imageName);
        m_image.setPixmap(QPixmap::fromImage(img));
    }
public:
    Widget(QWidget * parent = 0) : QWidget(parent), m_layout(this) {
        m_images << "redScreen.png" << "blueScreen.png" << "greenScreen.png";
        m_imageIt = m_images.begin();
        m_layout.addWidget(&m_name, 0, 0);
        m_layout.addWidget(&m_image, 1, 0);
        tick();
        m_timer.start(5000, Qt::CoarseTimer, this);
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}
person Kuba hasn't forgotten Monica    schedule 16.07.2014

Код, подобен на този по-долу, трябва да работи за задачата, която споменахте. (все пак се нуждае от почистване/организация на класа)

  QTimer timer;
  int x=0;
  QStringList images;
  QString imageName;


  MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),ui(new Ui::MainWindow){
   ui->setupUi(this);

   images << "redScreen.png" << "blueScreen.png" << "greenScreen.png";

   connect( &timer, SIGNAL(timeout()), this, SLOT(ChangeImageSlot()) );
   timer.start(5000);

}

void ChangeImageSlot()
{
   imageName = images.at(x++);
   this->displayScreen(imageName, 5);

   if( x < images.size() )
      timer.start(5000);
}
person DeepBlack    schedule 14.07.2014
comment
Няма нужда да рестартирате работещ таймер. Всъщност този код е грешен: вие трябва или да спрете работещия таймер в края на списъка с изображения, или да повторите индекса на списъка до нула, за да завъртите изображенията. Използването на целочислени индекси в контейнери в C++ също е малко подозрително. Итераторите са там с причина. - person Kuba hasn't forgotten Monica; 16.07.2014

Най-доброто решение е DeepBlack с няколко QTimer, но ако искате на свой риск, можете да опитате да поставите processEvent() функция вътре в цикъла for на показваното изображение.

person user473349    schedule 15.07.2014