2014-09-03 4 views
0

Мне нужно обработать и закрыть QFileDialog в тестах приложения. Диалог вызывается:Как закрыть QFileDialog программно?

QFileDialog::getOpenFileName(...); 

В тесте я 'поймать' этот диалог:

QApplication::topLevelWidgets(); 

Затем я выбираю нужен файл по QFileDialog API.

Теперь я должен закрыть диалог, чтобы получить правильный ответ (имя файла) из QFileDialog :: getOpenFileName(); Но слоты QDilaog не имеют эффекта (accept(), reject(), close() ...). Диалог остается открытым.

Решение, описанное here, работает, но в моем случае это не вариант. Я должен использовать стандартные диалоги.

Есть ли способ закрыть его правильно?

+0

«Тогда я выбираю нужный файл по API QFileDialog». Вы действительно видите изменения в графическом интерфейсе диалога? – Ezee

+0

Какую версию Qt вы используете? Я спрашиваю, потому что я смотрю на 4.8 источников, и он вообще не создает QFileDialog (вместо этого создается поддельный 'QDialog'). Итак, как вы используете API? – Ezee

+0

Да - каталог и файл выбраны правильно! – kaa

ответ

2

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(); 
+0

Как я уже сказал, я «поймаю» диалог между виджетами приложения. (Нет dlg-> getOpenFileName(); dlg-> close();) – kaa

+0

close() - не влияет на стандартный диалог. (Он работает только для диалога Qt). – kaa

+0

Я не понимаю, что вы подразумеваете под «стандартным диалогом». Код, добавленный в ответ, закрывает открытое диалоговое окно через 3 секунды после его открытия. – TheDarkKnight

1

В 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); 
+0

Спасибо, но мне нужно многоплатформенное решение. – kaa

+2

@ yuriy-velichko Я действительно сомневаюсь, что вам удастся найти кроссплатформенное решение. Windows-реализация использует winapi для вызова 'GetOpenFileName', который не возвращается, пока диалог не будет закрыт. Поэтому я должен быть специальным способом для закрытия такого диалога. И похоже, что он не реализован в Qt. – Ezee

+0

спасибо, Кажется, так оно и есть. – kaa

1

Для того, чтобы отобразите собственный диалог, вы должны запустить 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(); 
} 
Смежные вопросы