如何以编程方式关闭 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?的主要内容,如果未能解决你的问题,请参考以下文章

一种在 Mac 上强制关闭模态 QFileDialog 的方法

如何以编程方式关闭 Discord?

如何以编程方式关闭/禁用 NFC?

如何以编程方式单击剑道树视图节点[关闭]

如何以编程方式关闭通知托盘

如何在Tomcat上以编程方式自行关闭Spring应用程序