Всплывающее диалоговое окно для сохранения файла в отдельном потоке

У меня есть функция, которая вызывается в отдельном потоке от основного, когда кнопка нажимается, и она вызывает QFileDialog::getSaveFileName() функция, чтобы получить дескриптор файла для файла, сохраненного пользователем, но я не могу сделать это в отдельном потоке, потому что он изменяет графический интерфейс, и вам не разрешено это делать.

Как я могу обойти это?

1

Решение

В дополнение к комментариям относительно дизайна и чтения имен файлов из потока GUI перед созданием другого и передачей дескрипторов в качестве аргументов, я понимаю, что могут быть некоторые сценарии, когда вам нужно вызывать диалоги GUI из других потоков.

Одним из решений может быть излучение сигнала из вашего потока и захват в графическом интерфейсе. Недостатком этого подхода является то, что может быть трудно получить результат (имя файла в вашем случае).

Аналогичное решение заключается в использовании Qt::BlockingQueuedConnection вызывать метод объекта, живущего в потоке GUI, при этом блокируя другой поток, пока метод не вернется.

Следующий пример иллюстрирует это с помощью вспомогательного объекта:

class FileDialogCaller : public QObject {
Q_OBJECT

public:
FileDialogCaller(QObject* parent = 0) : QObject(parent) {
// The helper object will live in the GUI thread
moveToThread(qApp->thread());
}

// Add the rest of parameters as needed
QString getSaveFileName(QWidget* parent, const QString& caption, const QString& dir,
const QString& filter) {
QString fileName;

if (QThread::currentThread() != qApp->thread()) { // no GUI thread
QMetaObject::invokeMethod(this, "getSaveFileName_", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QString, fileName),
Q_ARG(QWidget*, parent),
Q_ARG(QString, caption),
Q_ARG(QString, dir),
Q_ARG(QString, filter));
} else { // in GUI thread, direct call
fileName = getSaveFileName_(parent, caption, dir, filter);
}

return fileName;
}

private:
Q_INVOKABLE
QString getSaveFileName_(QWidget* parent, const QString& caption, const QString& dir,
const QString& filter) {
return QFileDialog::getSaveFileName(parent, caption, dir, filter);
}
};

Чтобы использовать это просто:

QString fileName = FileDialogCaller().getSaveFileName(nullptr, "Save", "", "Any (*.*)");
2

Другие решения

QFileDialog::getSaveFileName() возвращает имя файла, он не пытается открыть файл или вернуть дескриптор файла.

Из вашего вопроса не ясно, но я предполагаю, что ваша кнопка запускает поток для выполнения некоторой длительной задачи и сохранения результатов в файле. Так что звоните QFileDialog::getSaveFileName() прямо в ячейке щелчка кнопки, получите имя файла и предоставьте это имя потоку. Ваша ветка просто прочитает это имя файла, поэтому, вероятно, нет необходимости в синхронизации. А затем вы просто открываете файл с указанным именем в этом потоке без графического интерфейса.

0

По вопросам рекламы [email protected]