У меня много времени на загрузку изображения (изображение большое), также некоторые операции над ним выполняются при загрузке. Я не хочу блокировать графический интерфейс приложения.
Моя идея состоит в том, чтобы загрузить изображение в другой поток, подать сигнал, что изображение загружено, а затем перерисовать представление с этим изображением.
Мой подход:
void Window::loadImage()
{
ImageLoader* loaderThread = new ImageLoader();
connect(loaderThread,SIGNAL(imageLoaded()),this,SLOT(imageLoadingFinished());
loaderThread->loadImage(m_image, m_imagesContainer, m_path);
}
void Window::imageLoadingFinished()
{
m_imagesContainer->addImage(m_image);
redrawView();
}
class ImageLoader : public QThread
{
Q_OBJECT
public:
ImageLoader(QObject *parent = 0) : m_image(NULL), m_container(NULL)
void loadImage(Image* img, Container* cont, std::string path)
{
m_image = img;
m_container = cont;
...
start();
}
signals:
void imageLoaded();
protected:
void run()
{
//loading image and operations on it
emit imageLoaded();
}
protected:
Image* m_image;
Container* m_container;
}
Я основывался на quedcustomtype
пример из Qt написания этого кода. При поиске и поиске в stackoverflow я также обнаруживаю, что подклассы QThread
не очень хорошая идея
Так что вопрос в том, как правильно это сделать? Как я уже сказал, я хочу неблокирующий графический интерфейс, загрузку и операции, выполняемые в другом потоке, и сигнал, который говорит, что загрузка завершена. После подачи сигнала вид должен быть перерисован.
Я не знаю много о многопоточности, но думаю, чтобы понять или иметь достаточно знаний, чтобы понять основные идеи.
Я полагаю, это лучший способ пойти:
#include <QApplication>
#include <QLabel>
#include <QThread>
class ImageLoader : public QObject
{
Q_OBJECT
public:
ImageLoader() : QObject() {
moveToThread(&t);
t.start();
}
~ImageLoader() {
qDebug("Bye bye!");
t.quit();
t.wait();
}
void requestImage(QString absPath) {
QMetaObject::invokeMethod(this, "loadImage", Q_ARG(QString, absPath));
}
public slots:
void loadImage(QString absPath) {
// Simulate large image.
QImage image(absPath);
sleep(10);
qDebug("Image loaded!");
emit imageReady(image);
}
signals:
void imageReady(QImage image);
private:
QThread t;
};
class MyLabel : public QLabel
{
Q_OBJECT
public:
MyLabel() : QLabel() {}
void mousePressEvent(QMouseEvent* ev) {
Q_UNUSED(ev);
qDebug("I got the event!");
}
public slots:
void setImage(QImage image) {
setPixmap(QPixmap::fromImage(image));
resize(image.width(), image.height());
qDebug("Image shown!");
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyLabel label;
label.show();
ImageLoader imageLoader;
QObject::connect(&imageLoader, SIGNAL(imageReady(QImage)), &label, SLOT(setImage(QImage)));
imageLoader.requestImage(some_abs_path);
return a.exec();
}
#include "main.moc"
Мне также нравится QtConcurrent, но учтите, что его использование как-то не рекомендуется: http://www.mail-archive.com/[email protected]/msg07794.html.
использование QtConcurent
фреймворк.
#include <QtConcurentRun>
#include <QFutureWatcher>
//....
class Window: public QWidget /*or something*/
{
//....
private:
QFutureWatcher<QImage> _wacther; //this object will signal when loading finished
};
//...
void Window::loadImage()
{
connect(&_watcher, SIGNAL(finished(), SLOT(finishLoading());
_wacther.setFuture(QtConcurent::run<QImage>(this, &Window::doLoadImage));
}
QImage Window::doLoadImage() //this function will be executed in the new thread. SHOULD BE Thread Safe
{
return someImage;
}
void window::finishLoading()
{
QImage result = _watcher.result();
}