Qt QImage和线程

Qt QImage和线程,qt,qthread,Qt,Qthread,我在QImages和Qthreads方面有问题。 我试图在线程中加载大图像,然后在QLabel上显示为QPixmap。 我的问题是,只要我不使用不同的线程来加载QImages,一切都是完美的,但只要我使用不同的线程,就没有什么是渲染器。 虽然我的QImage还有一个有效的尺寸 让我困惑的是,如果我只是注释cpp中将加载程序移动到另一个线程的第22行,标签就会显示得很好 有人有主意吗 下面是我非常简化的代码: 标题: 类加载器:公共QObject { Q_对象 公众: 显式加载器(QObject*

我在QImages和Qthreads方面有问题。 我试图在线程中加载大图像,然后在QLabel上显示为QPixmap。 我的问题是,只要我不使用不同的线程来加载QImages,一切都是完美的,但只要我使用不同的线程,就没有什么是渲染器。 虽然我的QImage还有一个有效的尺寸

让我困惑的是,如果我只是注释cpp中将加载程序移动到另一个线程的第22行,标签就会显示得很好

有人有主意吗

下面是我非常简化的代码: 标题:

类加载器:公共QObject { Q_对象 公众: 显式加载器(QObject*parent=0); 信号: 无效图像加载(QString、const QImage&); 公众时段: void loadImage(常量QString和fichier); }; 名称空间用户界面{ 类主窗口; } 类装入器图像; 类主窗口:公共QMainWindow { Q_对象 公众: 显式主窗口(QWidget*parent=0); ~main窗口(); 信号: 无效加载映像(常量字符串和档案); 专用插槽: 无效图像可用(常量字符串和档案、常量图像和img); 私人: Ui::MainWindow*Ui; //QString-mDossier; 装载机*mLoader; //QMap-mMapDesImages; 国际宽度; }; cpp:

#包括“mainwindow.h”
#包括“ui_main window.h”
#包括
#包括
#包括
#包括
#包括
#包括
#包括
主窗口::主窗口(QWidget*父窗口):
QMainWindow(父级),
ui(新ui::主窗口),
mLoader(新加载程序(NULL)),
mWidth(0)
{
用户界面->设置用户界面(此);
QThread*thread=新的QThread(此);
mLoader->moveToThread(线程);
线程->开始();
连接(此,信号(loadImage(QString)),mLoader,插槽(loadImage(QString));
连接(mLoader,SIGNAL(imageload(QString,QImage)),此,插槽(imageAvailable(QString,QImage));
发出loadImage(“C:/img.jpg”);
}
无效主窗口::图像可用(常量字符串和档案、常量图像和img)
{
mWidth+=(img.width()+20);
ui->mScrollContent->setMinimumSize(mWidth,img.height());
QLabel*lab=新的QLabel(ui->mScrollContent);
lab->setFixedSize(img.width(),img.height());
lab->setGeometry(mWidth-img.width()+20,0,img.width(),img.height());
lab->setPixmap(QPixmap::frommage(img));
}
MainWindow::~MainWindow()
{
删除mLoader;
删除用户界面;
}
加载器::加载器(QObject*父对象):
QObject(父对象)
{
}
无效加载程序::加载映像(常量QString和fichier)
{
QImage*image=新的QImage(fichier);
发射图像加载(菲希尔,*图像);
}

谢谢

有几个错误:

  • 你没有展示标签。当图像加载器位于GUI线程中时,将加载图像并在显示主窗口之前将标签添加到内容窗格中。由于显示了父对象,子对象将可见

    当加载在另一个线程中完成时,您将向已经显示的小部件添加图像标签。除非您显式地
    show()
    这些子窗口小部件,否则它们是不可见的

  • 您正在
    loadImage
    中泄漏图像。没有理由把
    QImage
    放在堆上

  • 您正在允许销毁正在运行的
    QThread
    。这是一个常见的错误,因为
    QThread
    基本上被设计破坏了。明智的C++类应该总是可破坏的。代码>QThread不是。因此,您需要一个变通方法

  • 您也没有设置内容小部件的最小高度

  • >P>您可能希望考虑使用<代码> QtAlp::运行< /COD>而不是专用线程。当您所执行的操作或多或少是一条直线时,这尤其值得。我已经展示了这两种实现,它们在运行时交替使用。请注意,您需要将
    concurrent
    模块和
    CONFIG+=c++11
    添加到项目文件中

  • 样式错误:

    • 对于已经为零的默认值参数,没有理由传递NULL

    • 如果将具有父对象生存期的
      QObject
      成员与父对象一起构造,则没有理由在堆上保留这些成员

    • 仅仅因为Qt Creator附带了愚蠢的模板文件,并不意味着您不应该使用
      std::unique_ptr
      QScopedPointer
      来保存
      ui
      成员。裸指针几乎不应该是成员,除非它们是指向父对象的
      QObjects

  • 由于缺少了相当多的代码,我真的无法判断还有什么可能是错误的。下面是一个完整的例子

    // https://github.com/KubaO/stackoverflown/tree/master/questions/image-loader-24853687
    #include <QtWidgets>
    #include <QtConcurrent>
    
    class Thread final : public QThread {
    public:
        ~Thread() { quit(); wait(); }
    };
    
    class Loader : public QObject
    {
        Q_OBJECT
    public:
        explicit Loader(QObject *parent = nullptr) : QObject(parent) {}
        Q_SIGNAL void imageLoaded(const QString &, const QImage &);
        Q_SLOT void loadImage(const QString& fichier) {
            QImage img(fichier);
            if (! img.isNull()) emit imageLoaded(fichier, img);
        }
    };
    
    class MainWindow : public QWidget
    {
        Q_OBJECT
        Loader m_loader;
        Thread m_loaderThread;
        QGridLayout m_layout{this};
        QPushButton m_open{"Open"};
        QScrollArea m_view;
        QWidget m_content;
        int m_width{};
        bool m_threadImpl = true;
        Q_SIGNAL void loadImage(const QString &);
        Q_SIGNAL void imageLoaded(const QString &, const QImage & img);
        Q_SLOT void imageAvailable(const QString &, const QImage & img) {
            int spacing = 20;
            if (m_width) m_width += spacing;
            auto lab = new QLabel(&m_content);
            lab->setFixedSize(img.width(), img.height());
            lab->setGeometry(m_width, 0, img.width(), img.height());
            lab->setPixmap(QPixmap::fromImage(img));
            lab->show();
            m_width += img.width();
            m_content.setMinimumWidth(m_width);
            m_content.setMinimumHeight(qMax(m_content.minimumHeight(), img.height()));
        }
        Q_SLOT void open() {
            auto dialog = new QFileDialog(this);
            dialog->setAttribute(Qt::WA_DeleteOnClose);
            dialog->show();
            if (m_threadImpl)
                connect(dialog, &QFileDialog::fileSelected, this, &MainWindow::loadImage);
            else
                connect(dialog, &QFileDialog::fileSelected, [this](const QString & fichier){
                    QtConcurrent::run([this, fichier]{
                        QImage img(fichier);
                        if (! img.isNull()) emit this->imageLoaded(fichier, img);
                    });
                });
            m_threadImpl = !m_threadImpl;
        }
    public:
        explicit MainWindow(QWidget *parent = nullptr) : QWidget(parent) {
            m_layout.addWidget(&m_open);
            m_layout.addWidget(&m_view);
            m_view.setWidget(&m_content);
            m_loader.moveToThread(&m_loaderThread);
            m_loaderThread.start();
            connect(&m_open, &QPushButton::clicked, this, &MainWindow::open);
            connect(this, &MainWindow::loadImage, &m_loader, &Loader::loadImage);
            connect(this, &MainWindow::imageLoaded, this, &MainWindow::imageAvailable);
            connect(&m_loader, &Loader::imageLoaded, this, &MainWindow::imageAvailable);
        }
    };
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
        return a.exec();
    }
    
    #include "main.moc"
    
    //https://github.com/KubaO/stackoverflown/tree/master/questions/image-loader-24853687
    #包括
    #包括
    类线程final:publicqthread{
    公众:
    ~Thread(){quit();wait();}
    };
    类加载器:公共QObject
    {
    Q_对象
    公众:
    显式加载程序(QObject*parent=nullptr):QObject(parent){}
    Q_信号无效图像加载(常量QString&,常量QImage&);
    Q_插槽无效加载映像(常量QString&fichier){
    QImage img(菲希尔);
    如果(!img.isNull())发出imageLoaded(fichier,img);
    }
    };
    类主窗口:公共QWidget
    {
    Q_对象
    装载机m_装载机;
    线程m_loaderThread;
    QGridLayout m_布局{this};
    QPushButton m_open{“open”};
    QScrollArea m_视图;
    qm_内容;
    int m_width{};
    bool m_threadImpl=true;
    Q_信号无效载荷图像(常数QString&);
    已加载Q_信号无效图像(常数Q字符串和、常数Q图像和img);
    Q_插槽无效映像可用(常量QString和、常量QImage和img){
    整数间距=20;
    如果(m_宽度)m_宽度+=间距;
    自动实验室=新的QLabel(&m_内容);
    lab->setFixedSize(img.width(),img.height());
    lab->setGeometry(m_width,0,img.width(),img.height());
    lab->setPixmap(QPixmap::frommage(img));
    实验室->显示();
    穆维
    
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QFile>
    #include <QPixmap>
    #include <QImage>
    #include <QDir>
    #include <QThread>
    #include <QDebug>
    #include <QLabel>
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow),
        mLoader(new Loader(NULL)),
        mWidth(0)
    {
        ui->setupUi(this);
    
        QThread* thread = new QThread(this);
        mLoader->moveToThread(thread);
        thread->start();
    
        connect(this, SIGNAL(loadImage(QString)), mLoader, SLOT(loadImage(QString)));
        connect(mLoader, SIGNAL(imageLoaded(QString,QImage)), this, SLOT(imageAvailable(QString,QImage)));
    
        emit loadImage("C:/img.jpg");
    }
    
    void MainWindow::imageAvailable(const QString &dossier, const QImage& img)
    {
        mWidth += (img.width() + 20);
        ui->mScrollContent->setMinimumSize(mWidth,img.height());
        QLabel* lab = new QLabel(ui->mScrollContent);
        lab->setFixedSize(img.width(), img.height());
        lab->setGeometry(mWidth - img.width() + 20, 0, img.width(), img.height());
        lab->setPixmap(QPixmap::fromImage(img));
    }
    
    MainWindow::~MainWindow()
    {
        delete mLoader;
        delete ui;
    }
    
    Loader::Loader(QObject *parent) :
        QObject(parent)
    {
    }
    
    
    void Loader::loadImage(const QString& fichier)
    {
        QImage* image = new QImage(fichier);
    
        emit imageLoaded(fichier, *image);
    }
    
    // https://github.com/KubaO/stackoverflown/tree/master/questions/image-loader-24853687
    #include <QtWidgets>
    #include <QtConcurrent>
    
    class Thread final : public QThread {
    public:
        ~Thread() { quit(); wait(); }
    };
    
    class Loader : public QObject
    {
        Q_OBJECT
    public:
        explicit Loader(QObject *parent = nullptr) : QObject(parent) {}
        Q_SIGNAL void imageLoaded(const QString &, const QImage &);
        Q_SLOT void loadImage(const QString& fichier) {
            QImage img(fichier);
            if (! img.isNull()) emit imageLoaded(fichier, img);
        }
    };
    
    class MainWindow : public QWidget
    {
        Q_OBJECT
        Loader m_loader;
        Thread m_loaderThread;
        QGridLayout m_layout{this};
        QPushButton m_open{"Open"};
        QScrollArea m_view;
        QWidget m_content;
        int m_width{};
        bool m_threadImpl = true;
        Q_SIGNAL void loadImage(const QString &);
        Q_SIGNAL void imageLoaded(const QString &, const QImage & img);
        Q_SLOT void imageAvailable(const QString &, const QImage & img) {
            int spacing = 20;
            if (m_width) m_width += spacing;
            auto lab = new QLabel(&m_content);
            lab->setFixedSize(img.width(), img.height());
            lab->setGeometry(m_width, 0, img.width(), img.height());
            lab->setPixmap(QPixmap::fromImage(img));
            lab->show();
            m_width += img.width();
            m_content.setMinimumWidth(m_width);
            m_content.setMinimumHeight(qMax(m_content.minimumHeight(), img.height()));
        }
        Q_SLOT void open() {
            auto dialog = new QFileDialog(this);
            dialog->setAttribute(Qt::WA_DeleteOnClose);
            dialog->show();
            if (m_threadImpl)
                connect(dialog, &QFileDialog::fileSelected, this, &MainWindow::loadImage);
            else
                connect(dialog, &QFileDialog::fileSelected, [this](const QString & fichier){
                    QtConcurrent::run([this, fichier]{
                        QImage img(fichier);
                        if (! img.isNull()) emit this->imageLoaded(fichier, img);
                    });
                });
            m_threadImpl = !m_threadImpl;
        }
    public:
        explicit MainWindow(QWidget *parent = nullptr) : QWidget(parent) {
            m_layout.addWidget(&m_open);
            m_layout.addWidget(&m_view);
            m_view.setWidget(&m_content);
            m_loader.moveToThread(&m_loaderThread);
            m_loaderThread.start();
            connect(&m_open, &QPushButton::clicked, this, &MainWindow::open);
            connect(this, &MainWindow::loadImage, &m_loader, &Loader::loadImage);
            connect(this, &MainWindow::imageLoaded, this, &MainWindow::imageAvailable);
            connect(&m_loader, &Loader::imageLoaded, this, &MainWindow::imageAvailable);
        }
    };
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
        return a.exec();
    }
    
    #include "main.moc"