QT:addLayout导致崩溃

时间:2019-05-21 19:59:56

标签: c++ qt pointers

我试图重写一个简单的“查找对话框”示例,而不使用指针作为类成员。我不知道为什么这段代码会导致此示例崩溃

//finddialog.h    
#ifndef FINDDIALOG_H
#define FINDDIALOG_H

#include<QtWidgets>
//#include <QDialog>


class FindDialog : public QDialog
{
    Q_OBJECT

public:
    FindDialog(QWidget *parent = 0);
    ~FindDialog();

signals:
    void findNext(const QString &str, Qt::CaseSensitivity cs);
    void findPrevious(const QString &str, Qt::CaseSensitivity cs);

private slots:
    void findClicked();
    void enablefindButton(const QString &text);
private:
    QLabel label{tr("Find &what:")};
    QLineEdit lineEdit;
    QCheckBox caseCheckBox{tr("Match &case")};
    QCheckBox backwardCheckBox{tr("Search &bacward")};
    QPushButton findButton{tr("&Find")};
    QPushButton closeButton{tr("&Close")};

};

#endif // FINDDIALOG_H

这是实现

//finddialog.cpp    
#include <QtWidgets>
#include "finddialog.h"

FindDialog::FindDialog(QWidget *parent)
    : QDialog(parent)
{

    label.setBuddy(&lineEdit);

    findButton.setDefault(true);
    findButton.setEnabled(false);

    connect(&lineEdit, SIGNAL(textChanged(const QString &)),
            this, SLOT(enablefindButton(const QString &)));
    connect(&findButton, SIGNAL(clicked()),
            this, SLOT(findClicked()));
    connect(&closeButton, SIGNAL(clicked()),
            this, SLOT(close()));

    QHBoxLayout topLeftLayout;
    topLeftLayout.addWidget(&label);
    topLeftLayout.addWidget(&lineEdit);

    QVBoxLayout leftLayout;
    leftLayout.addLayout(&topLeftLayout);
    leftLayout.addWidget(&caseCheckBox);
    leftLayout.addWidget(&backwardCheckBox);

    QVBoxLayout rightLayout;
    rightLayout.addWidget(&findButton);
    rightLayout.addWidget(&closeButton);
    rightLayout.addStretch();

    QHBoxLayout mainLayout{this};
    mainLayout.addLayout(&leftLayout);
    mainLayout.addLayout(&rightLayout);
    setLayout(&mainLayout);

    setWindowTitle(tr("Find"));
    setFixedHeight(sizeHint().height());
}

FindDialog::~FindDialog()
{

}

void FindDialog::findClicked()
{
    QString text = lineEdit.text();
    Qt::CaseSensitivity cs = caseCheckBox.isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive;

    if (backwardCheckBox.isChecked())
        emit findPrevious(text,cs);
    else
        emit findNext(text,cs);
}

void FindDialog::enablefindButton(const QString &text)
{
    findButton.setEnabled(!text.isEmpty());
}

主要就是这样

//main.cpp
#include <QApplication>
#include "finddialog.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    FindDialog w;
    w.show();

    return a.exec();
}

我发现问题出在方法'addLyout'上,即注释所有对该方法的调用,应用程序不会崩溃。从文档中,该方法需要一个指向QLayout的指针作为输入,因此我已经传递了每个布局的地址,但是缺少一些东西。您能帮我弄清楚发生了什么吗?

1 个答案:

答案 0 :(得分:1)

您的布局实例是堆栈变量,因此在构造函数返回后它们会被销毁。现在其他对象具有指向不再存在的实例的指针。这通常意味着当机。

将您的布局实例设为FindDialog的私有成员,以防止这种情况发生。

请注意,在堆栈上创建QObject实例时,需要注意声明顺序。当QObject被销毁时,它将删除其所有子对象,除非它们已被销毁。这意味着您需要确保小部件在布局之前被销毁。 (这对于所有具有父/子关系的QObjects都是这样,而不仅仅是布局。)如果您不注意这一点,则父级将尝试删除堆栈中的子级(显然不允许这样做)。 / p>

类成员的销毁顺序与构造顺序相反。因此,宣布最后一名成员首先被销毁。对于QLayout子类,需要在其子窗口小部件之后 销毁它们。因此,您需要先声明它们:

private:
    QHBoxLayout topLeftLayout;
    QVBoxLayout leftLayout;
    QVBoxLayout rightLayout;
    QHBoxLayout mainLayout{this};

    QLabel label{tr("Find &what:")};
    QLineEdit lineEdit;
    QCheckBox caseCheckBox{tr("Match &case")};
    QCheckBox backwardCheckBox{tr("Search &bacward")};
    QPushButton findButton{tr("&Find")};
    QPushButton closeButton{tr("&Close")};

这是为什么您看到的大多数Qt代码都在堆上(使用new分配QObject的原因之一。将它们放到堆上时,您不必担心此问题。显然,当拥有永远不会被删除的无父母对象时,您可能会遇到内存泄漏。所以选择你的毒药。