Функция не работает с QtConcurrent::run() при использовании QFutureWatcher
Я хочу вызвать функцию для удаления файлов и папок из системы в параллельном потоке, вызываемом QtConcurrent::run()
(Qt для встраиваемых Linux-систем 4.8). Используя только QFuture<bool>
с QFuture::waitForFinished()
чтобы получить результат (мне нужно запустить код сразу после операции), я смог заставить систему работать.
Но я хочу отобразить текущий результат операции в QProgressBar
производный класс с его setValue(int)
вызывается с помощью механизма сигналов и слотов внутри функции удаления, и то, что я получаю с помощью вышеупомянутого метода, является замороженным основным потоком, пока операция не завершена, и это недопустимо.
Так что я думал об использовании QFutureWatcher<bool>
и подключение это finished()
подайте сигнал в другой слот, содержащий оставшийся код, который будет запущен после завершения операции удаления.
Проблема, с которой я сталкиваюсь, заключается в том, что когда я делаю это, функция удаления просто не запускается QtConcurrent::run()
! Я проверил это с помощью печатных сообщений в терминал. Все, что происходит, это то, что QFutureWatcher
называет его finished()
сигнал без какого-либо выполнения функции удаления файлов (и это также происходит, если я использую QFutureWatcher::waitForFinished()
).
Это какая-то ошибка в Qt?
Что касается кода, он в точности такой же, как в Qt Assistant: создайте QFuture и QFutureWatcher глобально, соедините сигнал Finish () со слотом, вызовите QtConcurrent::run()
, а также setFuture()
в будущем. Ничего особенного.
Любая помощь приветствуется.
РЕДАКТИРОВАТЬ
Следуя просьбе Кубы, вот соответствующая часть кода:
//Declared globally in the .cpp
QFuture<bool> future;
QFutureWatcher<bool> watcher;
//
void SelectRecordToDeleteWidget::slotDeleteRecordStateMachine()
{
switch (deleteRecordStateMachine)
{
case PrepareToDelete:
{
//...
connect(&watcher,SIGNAL(finished()),this,SLOT(slotDeleteRecordStateMachine()),Qt::UniqueConnection);
//...
}
break;
case DeleteRecords:
{
//...
future = QtConcurrent::run(removeFiles, QString(DEFAULT_RECORD_DIR) + "/" + recordList.at(aaa).second.second, poProgressDialog, &itemCounter);
watcher.setFuture(future);
qApp->processEvents();
//...
}
break;
case FinishDelete:
{
//Run code after deleting files
}
break;
default:
break;
}
}
Это весь код, использующий QFuture и QFutureWatcher. removeFiles
выглядит следующим образом (не забывая, что он хорошо работает без QFutureWatcher):
bool removeFiles(const QString dirName, Interface::ProgressDialog* const poProgressDialog, qint32* const itemDeletedCounter)
{
bool result = true;
try
{
QDir dir(dirName);
if (dir.exists())
{
Q_FOREACH (QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst))
{
// if (Q_UNLIKELY(poProgressDialog->wasCanceled()))
// break;
if (info.isDir())
{
result = removeFiles(info.absoluteFilePath(),poProgressDialog,itemDeletedCounter);
if (!result)
return result;
}
else
{
result = QFile::remove(info.absoluteFilePath());
if (!result)
return result;
if (!QMetaObject::invokeMethod(poProgressDialog, "setValue",
Qt::BlockingQueuedConnection,
Q_ARG(qint32, *itemDeletedCounter)))
{
mDebugS(QString("removeFiles: %1QMetaObject::invokeMethod(poProgressDialog, \"setValue\"... failed!"));
}
++(*itemDeletedCounter);
// mDebugS(QString("removeFiles: %1").arg(*itemDeletedCounter));
}
}
result = dir.rmdir(dirName);
}
}
catch (...)
{
const QString strTemp = QString("An error in a call to removeFiles");
mDebugS(strTemp);
mLog(strTemp);
}
return result;
}