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

时间:2017-12-27 08:09:27

标签: c++ qt crash 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());
}

提前致谢!

2 个答案:

答案 0 :(得分:5)

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

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(); } 之前的范围。

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

data: {
    labels: chart_label,
    datasets: [{
        label: '# of Votes',
        data: chart_data,
        backgroundColor: [
            'rgba(255, 99, 132, 0.2)',
            'rgba(54, 162, 235, 0.2)',
            'rgba(255, 206, 86, 0.2)',
            'rgba(75, 192, 192, 0.2)',
            'rgba(153, 102, 255, 0.2)',
            'rgba(255, 159, 64, 0.2)'
        ],
        borderColor: [
            'rgba(255,99,132,1)',
            'rgba(54, 162, 235, 1)',
            'rgba(255, 206, 86, 1)',
            'rgba(75, 192, 192, 1)',
            'rgba(153, 102, 255, 1)',
            'rgba(255, 159, 64, 1)'
        ],
        borderWidth: 1
    }]
},

答案 1 :(得分:0)

您已自己删除了QMainWindow个元素:

delete this->lblHost;

QObject继承的对象与父对象一起在堆上创建时,您不应该自己删除它。因为QObject树将负责内存的内存管理。

所以将两次删除。