c++ - 在 Qt 中关闭 QMainWindow 后如何防止崩溃?

标签 c++ qt crash qmainwindow

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

enter image description here

但是,在我关闭窗口后,出现了这个错误:

The program has unexpectedly finished. The process was ended forcefully.

我的项目结构是:

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();
}

登录.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

登录.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));

您将它们作为布局小部件的父级,在本例中为您的登录主窗口,当调用父小部件析构函数时,所有子小部件都将被删除。您的代码中发生的情况是:子项(行编辑和标签)使用new 实例化,因此对它们调用 delete 会使您的应用程序崩溃。您应该用指针替换小部件 header 中的子声明,这样:

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 takes ownership of the widget pointer and deletes it at the appropriate time

正如 thuga 在评论中指出的那样,在堆栈上实例化子项本身并没有错,只要它们的析构函数在其父项的析构函数之前被调用,因此它们会自动从父项的子项列表中删除并且父项的析构函数不会调用删除它们。

如解释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();
}

关于c++ - 在 Qt 中关闭 QMainWindow 后如何防止崩溃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47988560/

相关文章:

c++ - libcurl,如何为每个句柄附加不同的回调函数?

c++ - 为什么在这种情况下类型 bool 的输出等于 0?

c++ - Qt 中的 JSON 类与 C++ 中的其他 JSON 解析器

ios: libswiftCore.dylib swift 崩溃

c++ - char WM_KEYDOWN 在硬编码时显示为数字且没有大写字母

c++ - 构造函数 MyClass(QWidget *parent = 0) 中 (QWidget *parent = 0) 的含义;

python - 绘制一个太大而无法放入 QImage 的图像

datagrid - datagrid粉碎ExpressionBlend 4

c++ - 变体和 _bstr_t 之间的转换导致 Windows 2008 中的不一致崩溃

c++ - 通过引用传递 C++