Я занимаюсь разработкой приложения Qt (версия 4.7.3 Qt) на плате SBC6000x.
У меня есть класс MessageBox, полученный из QDialog. Я сделал этот класс синглтон.
Всякий раз, когда должно быть показано окно сообщения, я использую метод .exec, чтобы показать его.
Есть несколько мест, где мне нужно показывать почтовые ящики один за другим.
Итак, чтобы показать новое окно сообщения, я должен закрыть предыдущее и показать новое.
например Когда окно сообщений открыто, и в то же время я получаю сообщение об ошибке из фона, я должен закрыть окно сообщений, которое отображается в данный момент, и показать сообщение с ошибкой.
Чтобы закрыть предыдущее диалоговое окно, я выставил метод CloseDlg из класса messagebox и пытался закрыть его.
Внутри этого CloseDlg я излучаю законченный сигнал.
void CMsgBox::CloseDlg()
{
if (NULL != CMsgBox::m_msgBox)
{
if(CMsgBox::m_msgBox->isVisible())
{
emit CMsgBox::m_msgBox->finished(0);
//QApplication::processEvents();
}
}
}
и называя это как
CMsgBox::CloseDlg();
Мой метод показа:
int CMsgBox::showMsgBox(Icon icon, const QString &textMsg, const QString &okBtnText)
{
if (CMsgBox::m_msgBox == NULL)
{
CMsgBox::m_msgBox = new CMsgBox();
}
CMsgBox::m_msgBox->setText(textMsg);
CMsgBox::m_msgBox->setIcon(icon);
CMsgBox::m_msgBox->setOkBtnText(okBtnText);
CMsgBox::m_msgBox->exec();
return CMsgBox::m_msgBox->m_btnPressed; //return, unblock the call
}
Снова, когда я вызываю showMsgBox, он показывает мне следующее предупреждение.
QDialog :: exec: обнаружен рекурсивный вызов
Проблема в том, что он не возвращается из предыдущего вызова exec (если мы не вернемся, как прокомментировано выше //).
Я пробовал то же самое с методами close (), accept (), reject () вместо события finish (), но ничего не получалось.
Как можно вернуться с предыдущего exe-вызова и достичь вышеописанного сценария? Любая помощь приветствуется.
То, что у вас здесь, выглядит как состояние гонки. Модальный QDialog запускает собственный цикл обработки событий, поэтому ваше приложение ведет себя как многопоточное приложение, и вам нужно позаботиться о параллелизме и условиях гонки.
Когда вы получаете секунду в вашем основном цикле событий, вы звоните CMsgBox::CloseDlg()
а также CMsgBox::showMsgBox()
в быстрой последовательности. Тем не мение, CloseDlg()
говорит циклу событий диалога вернуться, но CloseDlg()
фактически возвращается до очистки цикла событий диалога, и showMsgBox()
попытки позвонить exec()
в диалоге, который еще не завершен.
Что вам нужно сделать, это когда вы звоните CMsgBox::CloseDlg()
, подключитесь к finished(int)
сигнал, и только когда вы получаете finished(int)
ты можешь безопасно exec()
снова диалог
ПРИМЕЧАНИЕ. При подключении к finished(int)
сигнал, обязательно используйте Qt::QueuedConnection
вместо Qt::DirectConnection
который по умолчанию.
Итак, вам нужно немодальное диалоговое окно. Как объяснено в их документации:
Немодальные диалоги отображаются с помощью show (), который немедленно возвращает управление вызывающей стороне.
Поэтому вместо того, чтобы показывать окно с exec()
, покажи это с show()
,
Альтернатива методу show (), предложенному в другом ответе: QDialog::open()
. Он вернется, но все равно выдаст вам модальное диалоговое окно, поэтому остальная часть графического интерфейса будет отключена, пока вы не закроете его.