Reputation: 1367
I need to process and close QFileDialog in tests of the application. The dialog invoked by:
QFileDialog::getOpenFileName( ... );
In the test I 'catch' this dialog by:
QApplication::topLevelWidgets();
Then I choose need file by QFileDialog API.
And now I should close the dialog to get valid answer (filename) from QFileDialog::getOpenFileName(); But QDilaog's slots has no effect (accept(), reject(), close()... ). The dialog stays opened.
The solution described here works, but it is no option in my case. I must to use standard dialogs.
Is there a way to close it properly?
Upvotes: 1
Views: 5141
Reputation: 4350
In order for to display a native dialog, you have to run exec()
or call one of the static functions.
Unfortunately, in Windows, this calls a blocking function in the Windows API making the displayed dialog modal, running it's own event loop. Without returning to the Qt event loop, you cannot execute the close()
function using the signals/slots interface.
I tried to bypass this by calling the close()
function directly from another thread, but this results in Qt trying to send an event to the underlying dialog. Since sending (as opposed to posting) events across thread boundaries is not allowed in Qt, a fatal error is generated.
So, it seems for Windows at least, this is not possible.
I have not tested on platforms other than Windows. The code I used was:
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();
}
Upvotes: 2
Reputation: 27611
QFileDialog::getOpenFileName is a static method, so you're limited by what you can do with it.
If you want more control, I suggest creating an instance of QFileDialog and using that instead. By calling the instance's close() function, you can programmatically close the dialog.
In response to the comment that this doesn't work, here's example code:-
// 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();
Upvotes: 3
Reputation: 4344
In Windows you can use WinAPI to close the dialog:
#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);
Upvotes: 0