Abubaker Gaber
Abubaker Gaber

Reputation: 21

create a QThread to make changes

I'm trying to monitor changes in a folder using QFileSystemWatcher, and whenever changes happen they will be reflected in the GUI.

The idea is that I have a folder that gets updated every second with new images, and I need to display those images in sequence

nevertheless, the changes happen very fast, and the GUI freezes.

how can I make this line run in a different thread whenever there's a change in the folder.

QObject::connect(&watcher, SIGNAL(directoryChanged(QString)), w, SLOT(showModified(QString)));

or how can I make the code that creates reflections on the GUI run in a separate thread?

Upvotes: 0

Views: 116

Answers (1)

Alexey
Alexey

Reputation: 2479

To make QFileSystemWatcher work in a separate thread you can do:

  1. Create new thread - auto thread = new QThread;

  2. Create new file system watcher - auto watcher = new QFileSystemWatcher;

  3. Move watcher to thread - watcher->moveToThread(thread);

  4. Make connections

    connect(thread, &QThread::finished, watcher, &QObject::deleteLater);

    connect(thread, &QThread::finished, thread, &QObject::deleteLater);

    connect(watcher, &QFileSystemWatcher::directoryChanged, w, &<YourWidgetClassName>::showMidified, Qt::QueuedConnection);

  5. Start thread thread->start();

  6. Setup watcher with addPath or addPaths

  7. Do not forget call thread->quit(); when it's not needed or before application exits

So about problem of bunch images rendering in GUI.

I suggest you to use QImage to load and scale images for QPixmap to be created and rendered in GUI. Here QtConcurrent::run can be used per image to preform an image loading in a separate thread. It returns a QFuture object, that can be tracked with a QFutureWatcher object, that emits a finished signal, when a watched future is complete. Once connected to a QFutureWatcher::finished signal you can handle QFuture's result to assign a loaded QImage to QPixmap.

So, you need a code like this for QFileSystemWatcher::directoryChanged signal handler:

QStringList filenames = <some code to get new image filenames to render>;

auto loadImage = [](const QString &aFilename) -> QPixmap {
    auto image = QImage(aFilename).scaled(200, 200, Qt::KeepAspectRatio, Qt::SmoothTransformation);
    return QPixmap::fromImage(image);
};

for (auto &filename : filenames) {
    auto pixmap = QPixmap(200, 200); //create empty pixmap of desired size
    auto label = new QLabel;
    label->setPixmap(pixmap);
    m_layout->addWidget(label);

    auto future = QtConcurrent::run(loadImage, filename);
    auto watcher = new QFutureWatcher<QPixmap>(this);
    connect(watcher, &QFutureWatcher<QPixmap>::finished, this, [watcher, label]() { label->setPixmap(watcher->result()); });
    connect(watcher, &QFutureWatcher<QPixmap>::finished, watcher, &QFutureWatcher<QPixmap>::deleteLater);
    watcher->setFuture(future);
}

Upvotes: 1

Related Questions