I need to load a big file which is an .zip archive and contains two files: config and data. The loading progress consists of three stages: parse config, parse data, map data to more appropriate format. I need to do it in a separate thread. Also I need to display the progress and the stage in the progress dialog which contains QLabel for stage and QProgressBar for current stage progress.
After some studying of QtConcurrent I going to use code like this:
class OscillogramLoader : public QtConcurrent::ThreadEngine<Data>
{
public:
OscillogramLoader(QString filename);
protected:
QtConcurrent::ThreadFunctionResult threadFunction() override;
private:
QString m_filename;
};
QtConcurrent::ThreadFunctionResult OscillogramLoader::threadFunction()
{
futureInterfaceTyped()->setProgressRange(0, 50);
for (int i = 0; i < 50; ++ i)
{
if (isCanceled())
break;
futureInterfaceTyped()->setProgressValueAndText(i, "Parsing config");
QThread::msleep(100); // Real work will be here
}
futureInterfaceTyped()->setProgressRange(50, 250);
for (int i = 0; i < 200; ++ i)
{
if (isCanceled())
break;
futureInterfaceTyped()->setProgressValueAndText(50 + i, "Map data");
QThread::msleep(50); // Real work will be here
}
futureInterfaceTyped()->setProgressRange(250, 350);
for (int i = 0; i < 100; ++ i)
{
if (isCanceled())
break;
futureInterfaceTyped()->setProgressValueAndText(250 + i, "Map data");
QThread::msleep(80); // Real work will be here
}
reportResult(new OscillogramData()); // returning loaded data
return QtConcurrent::ThreadFinished;
}
....
QFutureWatcher<OscillogramData>* watcher = new QFutureWatcher<OscillogramData>();
QObject::connect(watcher, &QFutureWatcher<OscillogramData>::started, ...);
QObject::connect(watcher, &QFutureWatcher<OscillogramData>::progressRangeChanged, ...);
QObject::connect(watcher, &QFutureWatcher<OscillogramData>::progressTextChanged, ...);
QObject::connect(watcher, &QFutureWatcher<OscillogramData>::progressValueChanged, ...);
QObject::connect(watcher, &QFutureWatcher<OscillogramData>::finished, [=](){
OscillogramData data = watcher->result();
showData(&data);
watcher->deleteLater();
});
watcher->setFuture(QFuture<OscillogramData>(
QtConcurrent::startThreadEngine(new OscillogramLoader("/home/example/test1.zip"))));
....
Is it ok?
My old version of the loader class is inherited from QThread, has progressChanged, done, failure signals and overrided run method. Is it better or worse then previous code?
class OscillogramLoader : public QThread
{
Q_OBJECT
public:
explicit OscillogramLoader(QString filename, QObject* parent = nullptr);
QString filename() const;
bool isCanceled() const;
public slots:
void cancel();
signals:
void progressChanged(QString stage, double parcent);
void done(QString filaname, QSharedPointer<OscillogramData> data);
void failure(LoadFailureException exception);
protected:
void run() override;
private:
QString m_filename;
bool m_cancelled;
};