我有一个经典的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 DataSolverDialog::accept()
{
// do stuff when OK is clicked
}
注意,在函数CheckDirectoryPathanDupDateTree
中,我们使用new
声明了指向新QFileSystemModel对象的指针。 不能用此函数作用域中的delete
删除此指针,因为我希望模型持久化,以便UpdateImgSelection
可以使用它。 这似乎是QFileSystemModel对象的非常标准的用法,但是在C++中,我们被教导永远不要用new
实例化对象而不随后使用delete
释放内存。 我的问题是QFileSystemModel的这种用法是否会导致内存泄漏,如果是,如何避免?
欢迎来到C++和Qt的有趣世界。 你对“new”和“delete”的配对保持谨慎是正确的。 然而,Qt的引擎为您做了大量的对象管理。
简单的回答是:这不会导致内存泄漏
更长的简短回答:这不会导致内存泄漏。 您正在创建一个对象并告诉Qt该对象的父对象是'this'。 Qt现在将您的对象置于父子关系中,'this'是父对象,而您的新对象是子对象。 当删除父项时,子项也将随父项一起删除。
但是,请帮自己一个忙,花时间了解一下Qt如何处理对象,以及何时由您来照顾实例。 如果您不这样做,您可能会发现自己有非常令人沮丧的内存泄漏,看似随机的崩溃,或者“丢失”您认为应该存在的对象。
祝你好运,坚持下去。