Qt关闭QMainWindow后如何防止崩溃?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt关闭QMainWindow后如何防止崩溃?相关的知识,希望对你有一定的参考价值。

我有一个错误,在关闭我的应用程序后,我收到一条错误消息,说它已意外停止。我达到了这个:

enter image description here

但是,在关闭窗口后,我收到此错误:

该计划意外完成。这个过程有力地结束了。

我的项目结构是:

enter image description here

我的代码是:

main.cpp中

#include "mainwindow.h"
#include <QApplication>
#include <windows/login.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Login w;
    w.show();

    return a.exec();
}

util_window.h

#ifndef UTIL_H
#define UTIL_H

#include <QObject>
#include <QMainWindow>

class UtilWindow : QObject
{
public:
    // vars

    // methods
    util();
    void setCenterWindow(QMainWindow* w);
};

#endif // UTIL_H

util_window.cpp

#include "util_window.h"
#include <QDesktopWidget>

UtilWindow::util()
{

}

void UtilWindow::setCenterWindow(QMainWindow *w) {
    int width = w->frameGeometry().width();
    int height = w->frameGeometry().height();
    QDesktopWidget wid;
    int screenWidth = wid.screen()->width();
    int screenHeight = wid.screen()->height();
    w->setGeometry((screenWidth/2)-(width/2),(screenHeight/2)-(height/2),width,height);
    w->show();
}

login.h

#ifndef LOGIN_H
#define LOGIN_H

#include <QMainWindow>
#include <QObject>
#include <QWidget>
#include "util/util_window.h"
#include <QGroupBox>
#include <QLabel>
#include <QLineEdit>
#include <QFormLayout>

class Login : public QMainWindow
{
    Q_OBJECT
public:
    // vars
    UtilWindow* util;
    // widgets
    // labels
    QLabel* lblHost;
    QLabel* lblPort;
    QLabel* lblUser;
    QLabel* lblPass;
    // textbox
    QLineEdit* leHost;
    QLineEdit* lePass;
    QLineEdit* leUser;
    QLineEdit* lePort;
    // layouts
    QFormLayout* layout;
    QWidget* central;
    QVBoxLayout* mainLayout;
    QGroupBox* gbCredentials;
    // methods
    void initLabels();
    void initTextBoxes();
    void initUI();
    explicit Login(QWidget *parent = nullptr);
    ~Login();

signals:

public slots:
};

#endif // LOGIN_H

login.cpp

#include "login.h"

Login::Login(QWidget *parent) : QMainWindow(parent)
{
    this->util = new UtilWindow();
    this->initUI();

}

Login::~Login() {
    delete this->lblHost;
    delete this->lblPass;
    delete this->lblPort;
    delete this->lblUser;
    delete this->leHost;
    delete this->lePass;
    delete this->lePort;
    delete this->leUser;
    delete this->layout;
    delete this->central;
    delete this->mainLayout;
    delete this->gbCredentials;
    delete this->util;
}

void Login::initUI() {
    this->setFixedSize(400,400);
    this->setWindowTitle(tr("Inicio de sesión"));
    this->util->setCenterWindow(this);
    this->initLabels();
    this->initTextBoxes();
    this->layout = new QFormLayout();
    this->layout->addRow(this->lblHost, this->leHost);
    this->layout->addRow(this->lblPort, this->lePort);
    this->layout->addRow(this->lblUser, this->leUser);
    this->layout->addRow(this->lblPass, this->lePass);
    this->gbCredentials = new QGroupBox();
    this->gbCredentials->setTitle(tr("Datos de conexión"));
    this->gbCredentials->setLayout(layout);
    this->mainLayout = new QVBoxLayout();
    this->mainLayout->addWidget(gbCredentials);
    this->central = new QWidget();
    this->central->setParent(this);
    this->central->setLayout(this->mainLayout);
    this->setCentralWidget(this->central);
}

void Login::initLabels() {
    this->lblHost = new QLabel();
    this->lblPass = new QLabel();
    this->lblPort = new QLabel();
    this->lblUser = new QLabel();
    this->lblHost->setText(tr("Host: "));
    this->lblPass->setText(tr("Contraseña: "));
    this->lblPort->setText(tr("Puerto: "));
    this->lblUser->setText(tr("Usuario: "));
}

void Login::initTextBoxes() {
    this->leHost = new QLineEdit();
    this->lePass = new QLineEdit();
    this->lePort = new QLineEdit();
    this->leUser = new QLineEdit();
    this->leHost->setPlaceholderText(tr("Host de mysql"));
    this->lePass->setPlaceholderText(tr("Ingrese su contraseña"));
    this->leUser->setPlaceholderText(tr("Ingrese su nombre de usuario"));
    this->lePort->setPlaceholderText(tr("Ingrese el número de puerto"));
    this->leHost->setToolTip(this->leHost->placeholderText());
    this->leUser->setToolTip(this->leUser->placeholderText());
    this->lePass->setToolTip(this->lePass->placeholderText());
    this->lePort->setToolTip(this->lePort->placeholderText());
}

提前致谢!

答案

将小部件添加到布局时,例如

this->layout.addRow(&(this->lblHost), &(this->leHost));

你正在将它们添加到布局的小部件中,在这种情况下是你的Login主窗口,当调用父小部件析构函数时,所有子小部件都将是delete'd。您的代码中发生的事情是:子项(行编辑和标签)未使用new实例化,因此对它们调用delete将导致应用程序崩溃。您应该使用指针替换窗口小部件标头中的子声明,这样:

QLabel * lblHost;

// ...

QLineEdit * leHost;

// etc

并在将它们添加到布局之前实例化它们:

this->lblHost = new QLabel();
this->leHost = new QLineEdit();
this->layout.addRow(this->lblHost, this->leHost);
//etc

这适用于具有父级(即中央Qwidget)的所有布局和小部件。

另外:不需要在子节点上明确调用delete,因为父析构函数会处理它,这也适用于central widget

QMainWindow获取小部件指针的所有权并在适当的时候删除它

正如thuga在评论中指出的那样,在堆栈中实例化子进程没有任何内在错误,只要他们的析构函数在其父级之前被调用,因此它们会自动从父级子列表中删除,并且父析构函数不会在它们上调用delete

正如here所解释的那样,这是合法的:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QWidget widget;
    QLabel label(&widget);
    widget.show();

    return a.exec();
}

因为label将在widget之前超出范围。

更改两个对象创建顺序将导致应用程序在退出时崩溃:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QLabel label;
    QWidget widget;

    label.setParent(&widget);

    widget.show();

    return a.exec();
}

以上是关于Qt关闭QMainWindow后如何防止崩溃?的主要内容,如果未能解决你的问题,请参考以下文章

使用 QFileDialog 后 QMainWindow 进入后台

QT 程序在 connect() 后崩溃

Qt QMainWindow 用户关闭和系统中止之间的区别

Qt 中 QMainWindow 上的另一个窗口

Qt5 QMainWindow使用

尝试关闭 UIDocument 时防止崩溃