我有一个函数,当单击按钮时,它会在与主线程不同的线程中调用,它会调用该QFileDialog::getSaveFileName()
函数来获取用户保存的文件的文件句柄,但我不能在单独的线程上执行此操作,因为它修改 GUI,您不能这样做。
我怎样才能解决这个问题?
我有一个函数,当单击按钮时,它会在与主线程不同的线程中调用,它会调用该QFileDialog::getSaveFileName()
函数来获取用户保存的文件的文件句柄,但我不能在单独的线程上执行此操作,因为它修改 GUI,您不能这样做。
我怎样才能解决这个问题?
除了关于设计和在创建另一个线程之前从 GUI 线程读取文件名并将句柄作为参数传递的评论之外,我理解在某些情况下您可能需要从其他线程调用 GUI 对话框。
一种解决方案是从您的线程发出信号并在 GUI 中捕获。这种方法的缺点是可能很难获得结果(在您的情况下是文件的名称)。
一个类似的解决方案是使用 aQt::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 (*.*)");
QFileDialog::getSaveFileName()
返回文件名,它不尝试打开文件也不返回文件句柄。
您的问题尚不清楚,但我假设您的按钮启动线程以执行一些冗长的任务并将结果存储到文件中。因此QFileDialog::getSaveFileName()
,在按钮单击槽中直接调用,获取文件名并将该名称提供给线程。您的线程只会读取该文件名,因此可能不需要同步。然后,您只需在该非 GUI 线程中使用提供的文件名打开文件。