QFileSystemModel 对象会被删除吗?
Do QFileSystemModel objects ever get deleted?
我有一个经典的 QDialog,它使用 QFileSystemModel 填充 QTreeView,并具有过滤和处理用户选择的项目列表的功能。我是一个完全的 C++ 和 Qt 新手,所以我一直在关注大量的在线教程和示例。代码最终看起来像这样 [为简洁起见,内容匿名和编辑]:
在头文件中:
class MyExampleDialog : public QDialog
{
Q_OBJECT
public:
explicit MyExampleDialog(MyMainWidget *parent = nullptr);
~MyExampleDialog();
public slots:
virtual void accept() override;
private slots:
void directoryPathEntered();
void checkDirectoryPathAndUpdateTree(const QString& pathToCheck);
void validateSelection();
private:
QString getDirectoryPath() const;
QStringList updateFileSelection();
Ui::MyExampleDialog *_ui;
};
并在源文件中:
MyExampleDialog::MyExampleDialog(MyMainWidget *parent) :
QDialog(parent),
_ui(new Ui::MyExampleDialog)
{
_ui->setupUi(this);
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
_ui->directoryPathEdit->setText(getDirectoryPath());
checkDirectoryPathAndUpdateTree(getDirectoryPath());
QObject::connect(_ui->browseButton, &QPushButton::pressed, this, &MyExampleDialog::directoryPathEntered);
QObject::connect(_ui->directoryPathEdit, &QLineEdit::textChanged, this, &MyExampleDialog::checkDirectoryPathAndUpdateTree);
}
MyExampleDialog::~MyExampleDialog()
{
delete _ui;
}
void MyExampleDialog::directoryPathEntered()
{
const QString currentPath = getDirectoryPath();
QString newPath = QFileDialog::getExistingDirectory(this, tr("Select the installation directory"), currentPath);
if(newPath.isEmpty())
return;
_ui->directoryPathEdit->setText(newPath);
// then write newPath to QSettings
}
QString MyExampleDialog::getDirectoryPath() const
{
// retrieve path from QSettings
}
void MyExampleDialog::checkDirectoryPathAndUpdateTree(const QString& pathCheck)
{
if(std::filesystem::exists(pathCheck.toStdString()+"/bin/config.xml"))
{
QStringList filters;
filters << "*.jpeg";
QFileSystemModel *model = new QFileSystemModel(this);
model->setRootPath(pathCheck+QString::fromUtf8("/Images"));
model->setReadOnly(true);
model->setFilter(QDir::AllDirs | QDir::AllEntries | QDir::NoDotAndDotDot);
model->setNameFilters(filters);
_ui->imgTreeView->setModel(model);
_ui->imgTreeView->setRootIndex(model->setRootPath("/Images"));
_ui->imgTreeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
QObject::connect(_ui->imgTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MyExampleDialog::updateImgSelection);
QObject::connect(_ui->imgTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MyExampleDialog::validateSelection);
}
else
{
if(pathCheck.isEmpty()) { }
else
{
QMessageBox::critical(this, tr("Error"), tr("No config.xml file in installation /bin directory"));
}
_ui->imgTreeView->setModel(nullptr);
}
}
QStringList MyExampleDialog::updateImgSelection()
{
QItemSelectionModel *selModel = _ui->imgTreeView->selectionModel();
QModelIndexList selIndices = selModel->selectedIndexes();
QStringList imgSel;
QFileSystemModel *fsModel = static_cast<QFileSystemModel*>(_ui->imgTreeView->model());
foreach(QModelIndex index, selIndices)
{
// parse data to obtain file name
}
return imgSel;
}
void MyExampleDialog::validateSelection()
{
QStringList imgList = updateImgSelection();
if(! imgList.isEmpty())
{
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
}
else { _ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); }
}
void MyExampleDialog::accept()
{
// do stuff when OK is clicked
}
请注意,在函数 checkDirectoryPathAndUpdateTree
中,我们使用 new
声明了一个指向新 QFileSystemModel 对象的指针。不能在此函数范围内使用 delete
删除此指针,因为我希望模型持续存在,以便 updateImgSelection
可以使用它。这似乎是 QFileSystemModel 对象的标准用法,但在 C++ 中,我们被教导 never 使用 new
实例化对象,而无需随后使用 delete
释放内存.我的问题是 QFileSystemModel 的这种用法是否会导致内存泄漏,如果是,如何避免?
欢迎来到 C++ 和 Qt 的有趣世界。您对将 'new' 与 'delete' 配对是正确的。然而,Qt 的引擎为您做了很多对象管理。
简短的回答:这不会导致内存泄漏
较长的简短回答:这不会导致内存泄漏。您正在创建一个对象并告诉 Qt 这个对象的父对象是 'this'。 Qt 现在让您的对象处于父子关系中,'this' 是父对象,您的新对象是子对象。删除父项时,子项也会随之删除。
但是,请帮自己一个忙,花点时间了解 Qt 如何处理对象以及何时由您来处理实例。如果不这样做,您可能会发现自己遇到非常令人沮丧的内存泄漏、看似随机的崩溃或“丢失”您认为应该存在的对象。
祝你好运,坚持下去。
我有一个经典的 QDialog,它使用 QFileSystemModel 填充 QTreeView,并具有过滤和处理用户选择的项目列表的功能。我是一个完全的 C++ 和 Qt 新手,所以我一直在关注大量的在线教程和示例。代码最终看起来像这样 [为简洁起见,内容匿名和编辑]:
在头文件中:
class MyExampleDialog : public QDialog
{
Q_OBJECT
public:
explicit MyExampleDialog(MyMainWidget *parent = nullptr);
~MyExampleDialog();
public slots:
virtual void accept() override;
private slots:
void directoryPathEntered();
void checkDirectoryPathAndUpdateTree(const QString& pathToCheck);
void validateSelection();
private:
QString getDirectoryPath() const;
QStringList updateFileSelection();
Ui::MyExampleDialog *_ui;
};
并在源文件中:
MyExampleDialog::MyExampleDialog(MyMainWidget *parent) :
QDialog(parent),
_ui(new Ui::MyExampleDialog)
{
_ui->setupUi(this);
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
_ui->directoryPathEdit->setText(getDirectoryPath());
checkDirectoryPathAndUpdateTree(getDirectoryPath());
QObject::connect(_ui->browseButton, &QPushButton::pressed, this, &MyExampleDialog::directoryPathEntered);
QObject::connect(_ui->directoryPathEdit, &QLineEdit::textChanged, this, &MyExampleDialog::checkDirectoryPathAndUpdateTree);
}
MyExampleDialog::~MyExampleDialog()
{
delete _ui;
}
void MyExampleDialog::directoryPathEntered()
{
const QString currentPath = getDirectoryPath();
QString newPath = QFileDialog::getExistingDirectory(this, tr("Select the installation directory"), currentPath);
if(newPath.isEmpty())
return;
_ui->directoryPathEdit->setText(newPath);
// then write newPath to QSettings
}
QString MyExampleDialog::getDirectoryPath() const
{
// retrieve path from QSettings
}
void MyExampleDialog::checkDirectoryPathAndUpdateTree(const QString& pathCheck)
{
if(std::filesystem::exists(pathCheck.toStdString()+"/bin/config.xml"))
{
QStringList filters;
filters << "*.jpeg";
QFileSystemModel *model = new QFileSystemModel(this);
model->setRootPath(pathCheck+QString::fromUtf8("/Images"));
model->setReadOnly(true);
model->setFilter(QDir::AllDirs | QDir::AllEntries | QDir::NoDotAndDotDot);
model->setNameFilters(filters);
_ui->imgTreeView->setModel(model);
_ui->imgTreeView->setRootIndex(model->setRootPath("/Images"));
_ui->imgTreeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
QObject::connect(_ui->imgTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MyExampleDialog::updateImgSelection);
QObject::connect(_ui->imgTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MyExampleDialog::validateSelection);
}
else
{
if(pathCheck.isEmpty()) { }
else
{
QMessageBox::critical(this, tr("Error"), tr("No config.xml file in installation /bin directory"));
}
_ui->imgTreeView->setModel(nullptr);
}
}
QStringList MyExampleDialog::updateImgSelection()
{
QItemSelectionModel *selModel = _ui->imgTreeView->selectionModel();
QModelIndexList selIndices = selModel->selectedIndexes();
QStringList imgSel;
QFileSystemModel *fsModel = static_cast<QFileSystemModel*>(_ui->imgTreeView->model());
foreach(QModelIndex index, selIndices)
{
// parse data to obtain file name
}
return imgSel;
}
void MyExampleDialog::validateSelection()
{
QStringList imgList = updateImgSelection();
if(! imgList.isEmpty())
{
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
}
else { _ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); }
}
void MyExampleDialog::accept()
{
// do stuff when OK is clicked
}
请注意,在函数 checkDirectoryPathAndUpdateTree
中,我们使用 new
声明了一个指向新 QFileSystemModel 对象的指针。不能在此函数范围内使用 delete
删除此指针,因为我希望模型持续存在,以便 updateImgSelection
可以使用它。这似乎是 QFileSystemModel 对象的标准用法,但在 C++ 中,我们被教导 never 使用 new
实例化对象,而无需随后使用 delete
释放内存.我的问题是 QFileSystemModel 的这种用法是否会导致内存泄漏,如果是,如何避免?
欢迎来到 C++ 和 Qt 的有趣世界。您对将 'new' 与 'delete' 配对是正确的。然而,Qt 的引擎为您做了很多对象管理。
简短的回答:这不会导致内存泄漏
较长的简短回答:这不会导致内存泄漏。您正在创建一个对象并告诉 Qt 这个对象的父对象是 'this'。 Qt 现在让您的对象处于父子关系中,'this' 是父对象,您的新对象是子对象。删除父项时,子项也会随之删除。
但是,请帮自己一个忙,花点时间了解 Qt 如何处理对象以及何时由您来处理实例。如果不这样做,您可能会发现自己遇到非常令人沮丧的内存泄漏、看似随机的崩溃或“丢失”您认为应该存在的对象。
祝你好运,坚持下去。