Я использую Qt 5.1 и QtQuick 2.0 на Mac с OS-X 10.8.4.
Мой графический интерфейс Qt-QML перестает отвечать на запросы, потому что я блокирую цикл обработки событий с помощью операций ввода-вывода файла. Обычный подход к решению этой проблемы заключается в использовании нескольких потоков, как обсуждалось ВОТ Уилл Бикфорд.
Для этого я пытаюсь использовать:
QtConcurrent::blockingMapped()
что может быть проще, чем использование явного объекта QFuture. Я читал Qt docs а также классные примеры и получил следующий работающий код (смоделированный после этого пример):
// 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;
...
}
а вот заголовок и файлы реализации для 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) ...
}
Это не очень реалистично, но служит простым наброском для иллюстрации проблемы, с которой я столкнулся ниже.
Проблема возникает, когда я пытаюсь инкапсулировать QtConcurrent :: blockingMapped () в дополнительный класс «datamodel.h»:
#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;
}
И затем main () становится (обратите внимание, что я также переместил метод load () в класс DataModel):
#include <QList>
#include <iostream>
#include "dataobject.h"#include "datamodel.h"#include <QtConcurrent/QtConcurrentMap>
int main(int argc, char *argv[])
{
...
DataModel theModel;
theModel.runConcurrent();
...
}
Но теперь есть ошибка компилятора:
datamodel.cpp: error: reference to non-static member function must be called:
QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles, this->load);
Я не смог исправить ошибку компилятора путем инициализации экземпляра DataObject или DataModel (чтобы была видна нестатическая функция-член) и не был уверен, что еще можно попробовать.
Далее я подозреваю, что это может быть связано с проблемой привязки «functor» при настройке аргументов QtConcurrent (у меня не установлено boost, поэтому я не использую повышение :: BIND) так я и пытался Предложение мата использования C ++ 11 лямбда-выражений путем замены:
this->load
с:
[this](const QString& file){load(file);}
давая код:
QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles,
[this](const QString& file){load(file);});
Теперь я больше не получаю нестатическую ошибку члена, но возникает новая ошибка (указывает на строку выше):
datamodel.cpp: error: expected expression:
Я действительно пробил эту кроличью нору, вероятно, это простая ошибка, но мне трудно разобраться с этим.
Может кто-нибудь помочь?
Видимо, вы не используете C ++ 11 с лямбда-выражениями. Так что используйте привязки из STL или Boost или создайте объект функции.
QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles,
std::bind1st(std::mem_fun(&DataModel::load), this));
Хорошо, выше решение не может работать со ссылками (знаю ошибку). Определите функтор (или используйте Boost :: bind):
class LoadDataModel /*: public std::unary_function<QString, DataObject>*/ {
public:
LoadDataModel(DataModel *p) : d(p) {}
DataObject operator()(const QString &s) const {
return d->load(s);
}
private:
DataModel *d;
}
QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles, LoadDataModel(this));
Хорошо, получил это на работу.
В случае, если это может принести пользу тем, кто может не захотеть связываться с привязками или написать свой собственный «функтор» (подход ниже намного проще):
Начните с использования статического типа в файле datamodel.h для функции «load»:
static DataObject load(const QString& fileList);
Это работает, потому что статические функции класса C ++ могут быть вызваны без необходимости создания экземпляра объекта.
Затем в файле datamodel.cpp это так просто:
DataModel::load
дать:
QList<DataObject> allTheDataObjects =
QtConcurrent::blockingMapped(allFiles, DataModel::load);
Затем код работает, как ожидалось.