我有一个函数,当单击一个按钮时,它会在一个单独的线程中被调用,并调用QFileDialog::getSaveFileName()
函数来获取用户保存的文件的文件句柄,但我不能在单独的线程上执行此操作,因为它修改了GUI并且您不允许这样做。
我怎样才能解决这个问题?
答案 0 :(得分:2)
除了在创建另一个文件并将句柄作为参数传递之前有关设计和从GUI线程读取文件名的注释之外,我理解可能是某些需要从其他线程调用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 (*.*)");
答案 1 :(得分:0)
QFileDialog::getSaveFileName()
返回文件名,它不会尝试打开文件,也不会返回文件句柄。
从您的问题中不清楚,但我假设您的按钮启动线程执行一些冗长的任务并将结果存储到文件中。因此,在按钮单击槽中调用QFileDialog::getSaveFileName()
,获取文件名并将该名称提供给线程。您的线程将只读取该文件名,因此可能不需要同步。然后,您只需在该非GUI线程中使用提供的文件名打开该文件。