2013-08-10 5 views
1

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

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

ответ

0

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

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

2

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

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

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

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

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 (*.*)"); 
+0

Вы, вероятно, хотите проверить, что 'QThread :: currentThread() = qApp-> нить!() 'перед использованием Qt :: BlockingQueuedConnection. Просто позвоните 'getSaveFileName_' в этом случае – Caleth

+0

@Caleth Конечно! он принимал сценарий OP, но я согласен с вашим предложением – cbuchart