如何以编程方式关闭 QFileDialog?
Posted
技术标签:
【中文标题】如何以编程方式关闭 QFileDialog?【英文标题】:How to close QFileDialog programmatically? 【发布时间】:2014-09-03 08:25:24 【问题描述】:我需要在应用程序的测试中处理并关闭 QFileDialog。 调用的对话框:
QFileDialog::getOpenFileName( ... );
在测试中,我通过以下方式“捕捉”此对话框:
QApplication::topLevelWidgets();
然后我通过 QFileDialog API 选择需要的文件。
现在我应该关闭对话框以从 QFileDialog::getOpenFileName(); 获得有效的答案(文件名); 但是QDilaog的slots没有效果(accept(), reject(), close()...)。对话框保持打开状态。
here 描述的解决方案有效,但在我的情况下它不是选项。我必须使用标准对话框。
有没有办法正确关闭它?
【问题讨论】:
Then I choose need file by QFileDialog API.
。您真的在对话框的 GUI 中看到您的更改吗?
你使用什么 Qt 版本?我在问,因为我正在查看 4.8 源,它根本没有创建 QFileDialog(它创建了一个假的 QDialog
代替)。那么如何使用 API 呢?
是的 - 正确选择了目录和文件!
只需调用 QFileDialog::getOpenFileName(nullptr, message, QString(), mask);
但是您说您通过topLevelWidgets
找到了对话框,然后通过API 选择了一个文件。这意味着您使用的是指针而不是静态 API。否则你不需要找到对话框。
【参考方案1】:
QFileDialog::getOpenFileName 是一个静态方法,所以你会受到你能用它做什么的限制。
如果您想要更多控制,我建议创建一个 QFileDialog 实例并使用它。通过调用实例的close() 函数,您可以以编程方式关闭对话框。
针对这不起作用的评论,这里是示例代码:-
// Must create the FileDialog on the heap, so we can call close and the dialog is deleted
// Set the Qt::WA_DeleteOnClose flag if the instance is still required
QFileDialog* fileDlg = new QFileDialog(this, QString("Select Config file"), QDir::homePath(), QString("Config (*.xml)"));
// One shot timer to close the dialog programmatically
QTimer *timer = new QTimer(this);
timer->setSingleShot(true);
connect(timer, &QTimer::timeout, [=]()
fileDlg->close();
timer->deleteLater();
);
timer->start(3000);
fileDlg->exec();
【讨论】:
正如我所说,我“捕捉”了应用程序小部件之间的对话框。 (没有 dlg->getOpenFileName(); dlg->close();) close() - 对标准对话框无效。 (它只适用于 Qt 的对话框)。 我不明白你所说的“标准对话”是什么意思。我添加到答案中的代码会在打开对话框 3 秒后关闭打开的对话框。 @Merlin069,我认为“标准对话框”代表 Qt 使用的 Windows 本机文件打开/保存对话框。 @YuriyVelichko。当@Merlin069 说getOpenFileName()
是静态方法时,您还没有理解他的意思。如果您将dlg
作为QFileDialog*
的实例,则调用dlg->getOpenFileName()
对dlg
实例没有任何作用。显示的对话框是在静态函数中创建的 QFileDialog
的新实例。而是使用@Merlin069 在上面的答案中发布的代码。调用fileDlg->close()
将关闭对话框。我建议你研究一下什么是静态函数。【参考方案2】:
为了显示原生对话框,您必须运行 exec()
或调用其中一个静态函数。
不幸的是,在 Windows 中,这会调用 Windows API 中的阻塞函数,使显示的对话框成为模态,运行它自己的事件循环。如果不返回 Qt 事件循环,则无法使用信号/插槽接口执行 close()
函数。
我试图通过直接从另一个线程调用close()
函数来绕过此问题,但这会导致Qt 尝试将事件发送到底层对话框。由于在 Qt 中不允许跨线程边界发送(而不是发布)事件,因此会产生致命错误。
所以,至少对于 Windows 来说,这是不可能的。
我没有在 Windows 以外的平台上进行过测试。我使用的代码是:
int main(int argc, char *argv[])
QApplication a(argc, argv);
QFileDialog* fileDlg = new QFileDialog(0, QString("Select Config file"), QDir::homePath(), QString("Config (*.xml)"));
// spawn a new thread
QtConcurrent::run([=]()
QTimer timer;
timer.setSingleShot(true);
QEventLoop *loop = new QEventLoop;
QObject::connect(&timer, &QTimer::timeout, [=]()
fileDlg->close();
fileDlg->deleteLater();
loop->quit();
);
timer.start(3000);
loop->exec();
delete loop;
);
fileDlg->exec();
return a.exec();
【讨论】:
【参考方案3】:在 Windows 中,您可以使用 WinAPI 关闭对话框:
#define WAIT(A) while (!(A))
HWND dialogHandle, button;
WAIT(dialogHandle = FindWindow(NULL, L"Open")); //write here title of the dialog
WAIT(button = FindWindowEx(dialogHandle, NULL, L"Button", L"&Open")); //write here title of the button to click
SendMessage(button, BM_CLICK, 0, 0);
【讨论】:
谢谢,但我需要多平台解决方案。 @yuriy-velichko 我真的怀疑您能否成功找到跨平台解决方案。 Windows-implementaion 使用 winapi 调用GetOpenFileName
在对话框关闭之前不会返回。所以我应该是一种特定于平台的方式来关闭这样的对话框。而且看起来它没有在 Qt 中实现。以上是关于如何以编程方式关闭 QFileDialog?的主要内容,如果未能解决你的问题,请参考以下文章