打开窗口Qt时应用程序崩溃

打开窗口Qt时应用程序崩溃

问题描述:

我想创建一个程序,向用户显示一个带有一些答案的问题.我的应用程序使用3种形式:主菜单",登录菜单"和游戏表单",并且都继承自名为Form的抽象类.我这样做是因为它允许使用factory方法,当实际表单发出信号GoFw时,它将创建一个新窗口.

I would like to create a program that shows a question with some answers to the user. My application uses 3 forms: Main Menu, Login Menu and Game Form, and all inherit from an abstract class called Form; I do this because it allows the use of the factory method, which it create a new window when a signal GoFw is emitted by the actual form.

显示窗口的循环"如下:MainMenu-> LoginMenu-> GameForm-> MainMenu ... 问题是游戏结束后(例如,剩余问题的计数为零),GameForm发出信号GoFw,但应用程序在show()方法后崩溃(崩溃前我可以看到一个没有按钮的白色窗口). 调试器显示一个带有以下错误的消息框:

The "loop" that shows the windows is the following: MainMenu -> LoginMenu -> GameForm -> MainMenu... The problem is when the game is finished (e.g. the count of remaining questions is zero) the GameForm emits the signal GoFw but the application crashes after the show() method (I could see a white window with no buttons before the crash). The debugger show a messagebox with this error:

The inferior stopped because it triggered an exception.

Stopped in thread 0 by: Exception at 0x723f7b93, code: 0xc0000005: read access
violation at: 0x0, flags=0x0 (first chance).

然后QtCreator打开一个文件:Disassembler(QHash :: findNode)

and QtCreator opens a file called: Disassembler(QHash::findNode)

这是工厂方法的代码:

void FormFactory::Init(int formType)
{
    ///if formType == 1 MainMenu is showed
    if(formType == MAIN_MENU_TYPE)
    {
        //inizializza il puntatore
        actualForm = new MainMenu();
    }
    ///else if is == 2 show ProfileMenu
    else if(formType == PROFILE_MENU_TYPE)
    {
        actualForm = new LoginMenu();
    }
    ///else if == 3 show GameForm
    else if(formType == GAME_FORM_TYPE)
    {
        actualForm = new GameForm();
    }
    ///else if there is no match launch an exception
    else
        throw UnexpectedIdEx();

    connect(actualForm, SIGNAL(GoFw(int)), this, SLOT(DisplayForm(int)));
}

void FormFactory::DisplayForm(int i)
{
    Reset();
    Init(i);
    ///show the form pointed by actualform
    actualForm->show();
}

void FormFactory::Reset()
{
    disconnect(actualForm, SIGNAL(GoFw(int)), this, SLOT(DisplayForm(int)));
    ///if actualform is actually pointing to a form, delete it and set actualForm to zero
    if(actualForm!=0)
        delete actualForm;
    actualForm = 0;
}

MainMenu.cpp的代码是

And the code of MainMenu.cpp is

MainMenu::MainMenu()
{
    setUpGui();
}

void MainMenu::setUpGui()
{
    playButton = new QPushButton(tr("Play"));
    infoButton = new QPushButton(tr("Info"));
    quitButton = new QPushButton(tr("Exit"));

    ///connect the clicked signal to the related slot
    connect(infoButton, SIGNAL(clicked()), this, SLOT(info()));
    connect(quitButton, SIGNAL(clicked()), this, SLOT(quit()));
    connect(playButton, SIGNAL(clicked()), this, SLOT(emitSig()));

    ///create the vertical layout
    QVBoxLayout *layout = new QVBoxLayout;

    layout->addWidget(playButton);
    layout->addWidget(infoButton);
    layout->addWidget(quitButton);

    setLayout(layout);
    setWindowTitle(tr("Menu Principale"));
}

void MainMenu::emitSig()
{
    emit GoFw(2);
}

谢谢大家的帮助, 卢卡

Thank you all for your help, Luca

我建议您重新考虑您的解决方案,看来您将它与工厂方法一起过于复杂了. 只需对表单使用3个变量,对每个变量执行一次"new"操作,然后根据您的信号使用show()/hide()方法.

I'd suggest rethink your solution, it seems you overcomplicated it with the factory method. Just use 3 variables for the forms, do the "new" operation once for each, and use show() / hide() methods depending on your signals.

要回答崩溃问题,我看到的一个原因是因为您在插槽中执行了删除"操作. 来自Qt doc:

To answer to the crash problem, one reason i see is because you do "delete" in the slot. From Qt doc:

警告:在等待传递待处理事件时删除QObject可能导致崩溃.如果QObject与当前正在执行的线程不在同一线程中,则不能直接删除它.请改用deleteLater(),这将导致事件循环在所有未决事件传递到对象后删除该对象.

Warning: Deleting a QObject while pending events are waiting to be delivered can cause a crash. You must not delete the QObject directly if it exists in a different thread than the one currently executing. Use deleteLater() instead, which will cause the event loop to delete the object after all pending events have been delivered to it.