6

画像の読み込みに時間がかかります (画像が大きい)。また、読み込み時にいくつかの操作が行われます。アプリケーション GUI をブロックしたくありません。

私の考えは、別のスレッドに画像をロードし、画像がロードされたという信号を発してから、この画像でビューを再描画することです。

私のアプローチ:

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の例に基づいていました。スタックオーバーフローでグーグル検索して検索すると、サブクラス化QThreadはお勧めできないこともわかりました。

それで問題は、それを行う正しい方法は何ですか?私が言ったように、非ブロッキング GUI が必要で、読み込みと操作は別のスレッドで行われ、読み込みが完了したことを示す信号が表示されます。シグナルが発行された後、ビューを再描画する必要があります。 マルチスレッドについてはよくわかりませんが、基本的な考え方を理解したり、理解するのに十分な知識を持っていると思います。

4

2 に答える 2

7

フレームワークを使用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();
}
于 2012-12-14T12:43:02.300 に答える
3

これが最善の方法だと思います:

#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/development@qt-project.org/msg07794.html

于 2012-12-14T14:24:46.477 に答える