Pregunta

I am developing Qt application (Qt version 4.7.3) on SBC6000x board.

I have a MessageBox class derived from QDialog. I have made this class singleton.

Whenever a messagebox is to be show I am using .exec method to show it.

There are few places where I need to show messageboxes one after another.

So, to show new messagebox, I have to close previous one and show new one.

e.g. When Messagebox is open and at same time I receive an error from background I have to close the messagebox which is currently shown and show the one with error.

To closes previous dialog I have exposed CloseDlg method from messagebox class and trying to close it.

Inside this CloseDlg I am emitting finished signal.

void CMsgBox::CloseDlg()
{
    if (NULL != CMsgBox::m_msgBox)
    {
        if(CMsgBox::m_msgBox->isVisible())
        {
            emit CMsgBox::m_msgBox->finished(0);
            //QApplication::processEvents();
        }
    }
}

and calling it as

CMsgBox::CloseDlg();

My show method is :-

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
}

Again when I call showMsgBox,it is showing me following warning. QDialog::exec: Recursive call detected

Problem is, it doesn’t return from previous exec call (unless we return, as commented above //).

I tried same with close(), accept(), reject() methods instead of finished() event but nothing worked.

What is the way to return from previous exe call and achieve above scenario? Any help is welcome.

¿Fue útil?

Solución

What you have here looks like a race condition. A modal QDialog runs its own event loop, so your application behaves like a multithreaded application and you need to take care of concurrency and race conditions.

When you receive a second in your main event loop, you call CMsgBox::CloseDlg() and CMsgBox::showMsgBox() in quick succession. However, CloseDlg() tells the dialog's event loop to return, but CloseDlg() actually returns before the dialog's event loop is done cleaning up, and showMsgBox() attempts to call exec() on a dialog which hasn't finished exiting yet.

What you need to do is, when you call CMsgBox::CloseDlg(), connect to the finished(int) signal, and only when you receive the finished(int) can you safely exec() the dialog again.

NOTE: When connecting to the finished(int) signal, make sure to use a Qt::QueuedConnection instead of a Qt::DirectConnection which is the default.

Otros consejos

So, you need modeless dialog box. As explained in their documentation :

Modeless dialogs are displayed using show(), which returns control to the caller immediately.

Therefore, instead of showing the box with exec(), show it with show().

Alternative to show() method suggested in another answer is, use QDialog::open(). It will return, but will still give you modal dialog, so the rest of the GUI will be disabled until you close it.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top