【问题标题】:Trouble displaying sequence of images with setPixmap in Qlabel在 Qlabel 中使用 setPixmap 显示图像序列时出现问题
【发布时间】:2014-09-04 21:14:40
【问题描述】:

我正在尝试使用 setPixmap 通过 Qlabel 显示一系列图像。我有一个包含图像文件名的 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();
}

【问题讨论】:

  • 为什么在这种情况下使用 QEventLoop?
  • 我用它作为延迟

标签: qt qpixmap qlabel


【解决方案1】:

reentrant wait-via-eventloop hack 是难以诊断的错误的重要来源。不要使用它。您需要实例化自己的事件循环是非常非常罕见的。即使是相当复杂的项目也可以完全避免它。

您应该简单地运行一个计时器并对计时器的滴答声做出反应。这是一个例子:

#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();
}

【讨论】:

    【解决方案2】:

    类似于下面的代码必须适用于您提到的任务。 (虽然需要清洁/班级组织)

      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);
    }
    

    【讨论】:

    • 无需重新启动正在运行的计时器。事实上,这段代码是错误的:您必须要么在图像列表的末尾停止正在运行的计时器,要么将列表索引回收为零以循环图像。在 C++ 中在容器中使用整数索引也有点可疑。迭代器的存在是有原因的。
    【解决方案3】:

    最好的解决方案是带有几个 QTimer 的 DeepBlack,但如果你想冒险,你可以尝试在显示图像的 for 循环中插入一个 processEvent() 函数。

    【讨论】:

      猜你喜欢
      • 2010-10-29
      • 1970-01-01
      • 1970-01-01
      • 2018-02-13
      • 2022-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多