首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QImage和线程

QImage和线程
EN

Stack Overflow用户
提问于 2014-07-20 18:40:08
回答 1查看 3.4K关注 0票数 2

我在QImages和Q螺纹上遇到了问题。我正在尝试在线程中加载大图像,然后将它们显示为QPixmap在QLabel上。我的问题是,只要我不使用不同的线程来加载QImages,一切都是完美的,但一旦我使用了不同的线程,就没有什么是渲染器。尽管我的QImage仍然有一个有效的大小。

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

有谁有主意吗?

以下是我非常简化的代码: Header:

代码语言:javascript
复制
class Loader : public QObject
{
    Q_OBJECT
public:
    explicit Loader(QObject *parent = 0);

signals:
    void imageLoaded(QString, const QImage &);
public slots:
    void loadImage(const QString& fichier);
};

namespace Ui {
class MainWindow;
}
class LoaderImages;

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

signals:
    void loadImage(const QString& dossier);
private slots:
    void imageAvailable(const QString& dossier, const QImage& img);

private:
    Ui::MainWindow *ui;
    //QString mDossier;
    Loader* mLoader;
    //QMap<QString, QImage*> mMapDesImages;
    int mWidth;
};

cpp:

代码语言:javascript
复制
#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);
}

谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-07-21 05:07:52

有几个错误:

  1. 你没给我看标签。当图像加载器在GUI线程中时,将在主窗口显示之前加载图像并将标签添加到内容窗格中。由于显示的是父级,孩子就会变得可见。 当加载在另一个线程中完成时,您将向已经显示的小部件添加图像标签。这样的子小部件是,除非显式地show(),否则它们是不可见的。
  2. 你在loadImage上泄露图像。没有理由将这个QImage放到堆中。
  3. 您正在允许正在运行的QThread被销毁。这是一个常见的错误,因为QThread基本上被设计破坏了。理智的C++类应该始终是可销毁的。QThread不是,因此您需要一个解决办法。
  4. 您也没有设置内容小部件的最小高度。
  5. 您可能希望考虑使用QtConcurrent::run而不是专用线程。这是特别值得的,当您正在进行的操作是一个班轮,或多或少。我已经说明了这两个方面,在运行时实现是交替的。注意,您需要将concurrent模块和CONFIG += c++11添加到项目文件中。
  6. 风格错误:

代码语言:javascript
复制
- There's no reason to pass NULL for default-valued parameters that are already zero.
- There's no reason to keep `QObject` members that have the lifetime of the parent object on the heap, if such members are constructed along with the parent object.
- Just because Qt Creator comes with silly template files doesn't mean that you shouldn't be using a `std::unique_ptr` or `QScopedPointer` to hold the `ui` member. Naked pointers should almost never be members unless they're pointers to `QObjects` with parents. 

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

代码语言:javascript
复制
// 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"
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24853687

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档