Проблема с отображением последовательности изображений с помощью 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