I am running Qt 5.1 and QtQuick 2.0 on a Mac with OS-X 10.8.4.
My Qt-QML GUI becomes unresponsive because I am blocking the event loop with file I/O operations. The usual approach to solving it is to use multiple threads as discussed HERE by Will Bickford.
To do so, I am attempting to use:
QtConcurrent::blockingMapped()
which can be simpler than using an explicit QFuture object. I have been reading the Qt docs and cool examples and got the following code working (modeled after this example):
// NOTE: this all seems to work:
#include <QList>
#include <iostream>
#include "dataobject.h"
#include <QtConcurrent/QtConcurrentMap>
DataObject load(const QString &file) {
std::cout << "File I/O in thread = " << QThread::currentThread() << std::endl;
return DataObject anObject(file);
}
int main(int argc, char *argv[])
{
...
// Create a list of filenames:
int count = 5;
QList<QString> allFiles;
for (int i = 0; i < count; i++) {
allFiles.append(QString("aFileName"));
}
std::cout << "# of files = " << allFiles.size() << std::endl;
QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles,load);
std::cout << "# of objects = " << allTheDataObjects.size() << std::endl;
...
}
and here are the header and implementation files for DataObject:
#include <QString>
class DataObject
{
public:
DataObject();
DataObject(QString filename);
QString theFileName;
};
#include "dataobject.h"
DataObject::DataObject() {
theFileName = QString("no file");
}
DataObject::DataObject(QString filename) {
theFileName = filename;
//...
// Do file I/O stuff (slow) ...
}
This is not very realistic but serves as a simple sketch to illustrate the problem I encountered below.
The problem occurs when I try to encapsulate QtConcurrent::blockingMapped() within an additional "datamodel.h" class:
#include "dataobject.h"
class DataModel
{
public:
DataModel();
void runConcurrent();
DataObject load(const QString& fileList);
};
#include "datamodel.h"
#include <QtConcurrent/QtConcurrentMap>
#include <iostream>
DataModel::DataModel() {}
DataObject DataModel::load(const QString &file) {
std::cout << "File I/O in thread = " << QThread::currentThread() << std::endl;
return DataObject anObject(file);
}
void DataModel::runConcurrent() {
// Create a list of filenames:
int count = 5;
QList<QString> allFiles;
for (int i = 0; i < count; i++)
allFiles.append(QString("dummyFileName"));
QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles, this->load);
std::cout << "# of objects = " << allTheDataObjects.size() << std::endl;
}
And then main() becomes (note that I also moved the load() method into the DataModel class):
#include <QList>
#include <iostream>
#include "dataobject.h"
#include "datamodel.h"
#include <QtConcurrent/QtConcurrentMap>
int main(int argc, char *argv[])
{
...
DataModel theModel;
theModel.runConcurrent();
...
}
But now there is a compiler error:
datamodel.cpp: error: reference to non-static member function must be called:
QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles, this->load);
I was not able to fix the compiler error by initializing a DataObject or DataModel instance (so that a non-static member function could be visible) and wasn't sure what else to try.
Next I suspected this could be due to a problem with "functor" bindings when setting up the QtConcurrent arguments (I don't have boost installed so am not using boost::bind) so I tried Mat's suggestion of using C++ 11 lambdas by replacing:
this->load
with:
[this](const QString& file){load(file);}
giving the code:
QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles,
[this](const QString& file){load(file);});
Now I no longer get the non-static member error, but a new error occurs (pointing at the above line):
datamodel.cpp: error: expected expression:
I've really gotten down a rabbit hole on this one, its probably a simple mistake but I am having trouble sorting it out.
Can someone help?