C++ 如何在静态单例类中以编程方式从exec方法返回

C++ 如何在静态单例类中以编程方式从exec方法返回,c++,qt,singleton,qdialog,C++,Qt,Singleton,Qdialog,我正在SBC6000x板上开发Qt应用程序(Qt版本4.7.3) 我有一个从QDialog派生的MessageBox类。我把这门课改成了单身 无论何时显示messagebox,我都使用.exec方法来显示它 很少有地方需要一个接一个地显示MessageBox 所以,要显示新的messagebox,我必须关闭前一个messagebox并显示新的messagebox e、 g.当Messagebox打开,同时我从后台收到一个错误时,我必须关闭当前显示的Messagebox并显示有错误的Message

我正在SBC6000x板上开发Qt应用程序(Qt版本4.7.3)

我有一个从QDialog派生的MessageBox类。我把这门课改成了单身

无论何时显示messagebox,我都使用.exec方法来显示它

很少有地方需要一个接一个地显示MessageBox

所以,要显示新的messagebox,我必须关闭前一个messagebox并显示新的messagebox

e、 g.当Messagebox打开,同时我从后台收到一个错误时,我必须关闭当前显示的Messagebox并显示有错误的Messagebox

为了关闭上一个对话框,我从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()方法,而不是finished()事件,但没有任何效果

如何从先前的exe调用返回并实现上述场景?欢迎任何帮助。

因此,您需要帮助。如其文件中所述:

使用show()显示无模式对话框,它会立即将控制权返回给调用方


因此,不要用
exec()
显示框,而是用
show()
显示框。另一个答案中建议的show()方法的替代方法是使用。它将返回,但仍然会给您提供模式对话框,因此在您关闭它之前,GUI的其余部分将被禁用。

您在这里看到的看起来像是竞争条件。模态QDialog运行自己的事件循环,因此您的应用程序的行为类似于多线程应用程序,您需要注意并发性和竞争条件

当您在主事件循环中接收到第二个事件时,可以快速连续调用
CMsgBox::CloseDlg()
CMsgBox::showMsgBox()
。但是,
CloseDlg()
告诉对话框的事件循环返回,但是
CloseDlg()
实际上在对话框的事件循环清理完成之前返回,并且
showMsgBox()
尝试对尚未完成退出的对话框调用
exec()

你需要做的是,当你调用
CMsgBox::CloseDlg()
时,连接到
finished(int)
信号,只有当你收到
finished(int)
时,你才能安全地
exec()
再次打开对话框


注意:连接到
finished(int)
信号时,请确保使用
Qt::QueuedConnection
而不是默认的
Qt::DirectConnection

如果由于性能原因,应用程序显示的错误消息太多,需要单音消息框来显示这些消息。。。用户将看到什么?最后一个错误?一个接一个的错误?它被称为ErrorOnlyApplication?错误是一种罕见的情况。用户应该能够看到带有指定错误的最新消息框。那么为什么要保留消息框的分配?你有内存碎片问题吗?如果在运行时创建窗口,我会在应用程序开始时创建所有窗口,并在需要时显示它们。这还包括一个messagebox。(我知道这不是完美的方法,我正在保存创建屏幕的运行时处理并投资于内存使用)您是否尝试过在运行时更改消息框的文本?(不知道这是否有效)。作为一个侧节点,我推荐阅读,它确实改变了我对单音的看法谢谢你,我只想让它保持模态。保持无模式立即返回。如果我有两个按钮确定和取消和取消是我的默认值。它立即返回该值,这是不期望的。我只想将其保持为模态。保持无模式立即返回。如果我有两个按钮确定和取消和取消是我的默认值。它会立即返回该值,这是不期望的。谢谢你,弗雷德,我试过了。在收到“finished”事件后,我试图调用exec,但它仍然给了我“QDialog::exec:检测到递归调用”。我认为,它不能立即脱离其状态,并且作为一个单态对象,它会妨碍下一次调用。我们需要找到一个对象上可调用exec的逻辑点,它没有任何等待条件。@RajendraW:当附加到“finished”信号时,您是否确保该序列为排队序列而不是默认的直接连接类型?这里使用“multithreaded”和“concurrency”有点误导。本地事件循环在exec()内完全同步执行,但由于任何事件都可能发生并触发任意事件处理程序/插槽,因此在exec()返回并销毁对应用程序状态所做的任何假设之前,都可以执行(在同一线程中)。这与临界截面相似,是的。OTOH它也简单得多,而锁定等多线程概念也无助于解决这个问题。最简单的方法是:不要弄乱事件循环:不要使用exec()、processEvents()或显式本地事件循环。@Fred:您的解决方案工作得很好,使用Qt::QueuedConnection的connect调用有助于使用“done”函数关闭第一个messagebox。一旦第一个接收到“完成”信号,我们就可以显示下一个messagebox。