QT: addLayout вызывает сбой - PullRequest
0 голосов
/ 21 мая 2019

Я пытался переписать простой пример "диалога поиска" без использования указателя в качестве членов класса. Я не могу понять, почему этот код вызывает сбой этого примера

//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 Ответ

1 голос
/ 21 мая 2019

Ваши экземпляры макета являются переменными стека, поэтому они разрушаются после возврата конструктора.Другие объекты теперь имеют указатели на экземпляры, которые больше не существуют.Это обычно означает сбой.

Сделайте ваши экземпляры макета закрытыми членами FindDialog, чтобы этого не происходило.

Обратите внимание, что при создании экземпляров QObject в стеке вы должны быть осторожны спорядок декларирования.Когда QObject будет уничтожен, он удалит все свои дочерние объекты, если они не были уничтожены.Это означает, что вам нужно убедиться, что ваши виджеты уничтожены, прежде чем их макеты это сделают.(Это относится ко всем объектам QObject с отношениями родитель / потомок, а не только к макетам.) Если вы не обращаете на это внимания, родители попытаются удалить дочерние элементы, которые находятся в стеке (что, очевидно, недопустимо).

Порядок уничтожения членов класса является обратным порядку построения.Таким образом, члены, объявленные последними, уничтожаются первыми.В случае подклассов 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, который вы видите там, вместо этого выделяет объекты QObject в куче (с new).Вам не придется беспокоиться об этой проблеме, когда вы кладете их в кучу.Очевидно, что вы можете столкнуться с утечками памяти, когда объекты без родителей никогда не удаляются.Так что выбирай свой яд.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...