当我从树模型中删除树项时,不会调用树项的析构函数。
这是我用于从模型中删除树项的代码。
void TreeModel::removeItem(TreeItem *node)
{
const int row = node->row();
QModelIndex idx = createIndex(row, 0, node);
TreeItem* itm = getItem(idx);
beginRemoveRows(idx.parent(), row, row);
node->parent()->removeChild(row);
endRemoveRows();
}
Treeitem RemoveChild的代码。
void TreeItem::removeChild(int row)
{
childItems.removeAt(row);
}
树项头文件的代码。
#include <QList>
#include <QVariant>
#include <QVector>
#include "Container.h"
class TreeItem
{
public:
explicit TreeItem( Container *data , TreeItem *parent = 0 );
~TreeItem();
TreeItem *parent();
void appendChild(TreeItem *child);
TreeItem *child(int iNumber);
int childCount() const;
int childNumber() const;
Container data() const ;
Container* GetContainer();
bool setData(Container* data , QVariant value);
void setContainer( Container* data);
bool insertChildren(int position, int count );
bool removeChildren( int position , int count );
void removeChild(int row);
void removeChild(TreeItem* itm);
std::string getChildName(int row);
std::string getName();
int row() const;
void insertChild(int pos, TreeItem *child);
private:
QList<TreeItem*> childItems;
Container* itemData;
TreeItem* parentItem;
};
树项 Cpp 文件的代码。///////////////////////////////////////////////////////////////////////////////////////////////////
TreeItem::TreeItem( Container *data, TreeItem *parent )
{
parentItem = parent;
itemData = new Container;
*itemData = *data;
}
TreeItem::~TreeItem()
{
qDebug() << itemData->GetName().c_str();
if (itemData != nullptr)
{
delete itemData;
qDebug() << "deleting Item Data";
}
qDeleteAll(childItems);
}
TreeItem *TreeItem::parent()
{
return parentItem;
}
TreeItem *TreeItem::child(int iNumber)
{
return childItems.value(iNumber);
}
int TreeItem::childCount() const
{
return childItems.count();
}
int TreeItem::childNumber() const
{
if (parentItem)
return parentItem->childItems.indexOf(const_cast<TreeItem*> (this));
return 0;
}
Container TreeItem::data() const
{
return *itemData;
}
bool TreeItem::setData( Container* data , QVariant value )
{
//*itemData = *data; // Do Not !!!! uncomment this as it will set the
value of default container constructor.
itemData->SetName(value.toString().toStdString() );
return true;
}
bool TreeItem::insertChildren(int position, int count)
{
if (position < 0 || position > childItems.count())
return false;
Container cont;
TreeItem *item = new TreeItem(&cont, this);
childItems.insert(position, item);
return true;
}
bool TreeItem::removeChildren(int position, int count)
{
if (position < 0 || position > childItems.count())
return false;
for (int row = 0; row < count; ++row)
{
delete childItems.takeAt(position);
}
return true;
}
void TreeItem::setContainer( Container* cont)
{
*itemData = *cont;
}
void TreeItem::appendChild(TreeItem *node)
{
childItems.append( node );
}
int TreeItem::row() const
{
if (parentItem)
return parentItem->childItems.indexOf( const_cast<TreeItem*>(this) );
return 0;
}
void TreeItem::removeChild(int row)
{
childItems.removeAt(row);
}
void TreeItem::insertChild(int pos, TreeItem *child)
{
childItems.insert(pos, child);
child->parentItem = this;
}
void TreeItem::removeChild(TreeItem* itm)
{
childItems.removeOne(itm);
}
std::string TreeItem::getChildName(int row)
{
return childItems.value(row)->getName();
}
std::string TreeItem::getName()
{
return itemData->GetName();
}
Container* TreeItem::GetContainer()
{
return itemData;
}
树模型类
///#pragma once
#include <QAbstractItemModel>
#include <QString>
#include <QMimedata.h>
#include <Qdatastream.h>
class TreeItem;
class Container;
class TreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
TreeModel(const QString &header, Container *data, QObject *parent = 0);
~TreeModel();
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
bool setHeaderData(int section, Qt::Orientation orientation,
const QVariant &value, int role = Qt::EditRole) override;
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
QModelIndex parent(const QModelIndex &parent) const override;
bool insertRows(int position, int rows, const QModelIndex &parent);
// bool removeRows(int position, int rows, const QModelIndex &parent = QModelIndex()) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
Container* GetContainer(const QModelIndex &index);
void SetContainer(const QModelIndex &index, Container* cont);
////////////////////// Drag And Drop Actions ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Qt::DropActions supportedDropActions() const override;
Qt::DropActions supportedDragActions() const override;
QStringList mimeTypes() const override;
QMimeData *mimeData(const QModelIndexList &indexes) const override;
bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
void setupModelData(const QStringList &lines, TreeItem *parent);
void removeItem(TreeItem *item);
bool FindChild(std::string stdstrChildName);
TreeItem *getItem(const QModelIndex &index) const;
TreeItem *getRoot();
private:
//void setupModelData(const Container &cont, TreeItem *parent);
TreeItem *rootItem;
};
树模型的 Cpp 文件
#include "TreeModel.h"
#include "TreeItem.h"
#include <qcoreapplication.h>
#include <qdebug.h>
#include "Container.h"
TreeItem *TreeModel::getItem(const QModelIndex &index) const
{
if (index.isValid()) {
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
if (item)
return item;
}
return rootItem;
}
TreeModel::TreeModel(const QString &header, Container *data, QObject
*parent) : QAbstractItemModel(parent)
{
qDebug() << "First level done";
rootItem = new TreeItem( data);
}
TreeModel::~TreeModel()
{
delete rootItem;
}
QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (role != Qt::DisplayRole && role != Qt::EditRole)
return QVariant();
TreeItem *item = getItem(index);
return QString::fromStdString(item->data().GetName());
//return QVariant::fromValue(item->data());
}
QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return QVariant::fromValue(rootItem->data());
return QVariant();
}
bool TreeModel::setData(const QModelIndex &index, const QVariant &val, int
role)
{
if (role != Qt::EditRole)
return false;
Container c = val.value<Container>();
TreeItem *item = getItem(index);
bool result = true;
item->setData(&c, val);
if (result)
emit dataChanged(index, index, { role });
return result;
}
QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent)
const
{
if (parent.isValid() && parent.column() != 0)
return QModelIndex();
TreeItem *parentItem = getItem(parent);
TreeItem *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
}
QModelIndex TreeModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
TreeItem *childItem = getItem(index);
TreeItem *parentItem = childItem->parent();
if (parentItem == rootItem)
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
bool TreeModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &val, int role)
{
if (role != Qt::EditRole || orientation != Qt::Horizontal)
return false;
Container c = val.value<Container>();
bool result = rootItem->setData(&c, val);
if (result)
emit headerDataChanged(orientation, section, section);
return result;
}
bool TreeModel::insertRows(int position, int rows, const QModelIndex &parent)
{
TreeItem *parentItem = getItem(parent);
bool success;
beginInsertRows(parent, position, position + rows - 1);
success = parentItem->insertChildren(position, rows);
endInsertRows();
return success;
}
Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::ItemIsDropEnabled;
return QAbstractItemModel::flags(index) | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEditable;
}
int TreeModel::rowCount(const QModelIndex &parent) const
{
if (parent.column() > 0)
return 1;
TreeItem *parentItem = getItem(parent);
//qDebug() << "the child count = " << parentItem->childCount() << parentItem->data().GetName().c_str();
return parentItem->childCount();
}
int TreeModel::columnCount(const QModelIndex & /* parent */) const
{
return 1;
}
Container* TreeModel::GetContainer(const QModelIndex &index)
{
TreeItem *item = getItem(index);
return item->GetContainer();
}
void TreeModel::SetContainer(const QModelIndex &index, Container* Cont)
{
TreeItem *item = getItem(index);
item->setContainer(Cont);
}
static const char s_treeNodeMimeType[] = "application/x-treenode";
QStringList TreeModel::mimeTypes() const
{
return QStringList() << s_treeNodeMimeType;
}
QMimeData *TreeModel::mimeData(const QModelIndexList &indexes) const
{
QMimeData *mimeData = new QMimeData;
QByteArray data; //a kind of RAW format for datas
//QDataStream is independant on the OS or proc architecture
//serialization of C++'s basic data types, like char, short, int, char *, etc.
//Serialization of more complex data is accomplished
//by breaking up the data into primitive units.
QDataStream stream(&data, QIODevice::WriteOnly);
QList<TreeItem *> nodes;
//
foreach(const QModelIndex &index, indexes) {
TreeItem *node = getItem(index);
if (!nodes.contains(node))
nodes << node;
}
stream << QCoreApplication::applicationPid();
stream << nodes.count();
foreach(TreeItem *node, nodes) {
stream << reinterpret_cast<qlonglong>(node);
}
mimeData->setData(s_treeNodeMimeType, data);
return mimeData;
}
bool TreeModel::dropMimeData(const QMimeData *mimeData, Qt::DropAction
action, int row, int column, const QModelIndex &parent)
{
//Q_ASSERT(action == Qt::MoveAction);
//Q_UNUSED(column);
//test if the data type is the good one
if (!mimeData->hasFormat(s_treeNodeMimeType)) {
return false;
}
QByteArray data = mimeData->data(s_treeNodeMimeType);
QDataStream stream(&data, QIODevice::ReadOnly);
qint64 senderPid;
stream >> senderPid;
if (senderPid != QCoreApplication::applicationPid()) {
// Let's not cast pointers that come from another process...
return false;
}
TreeItem *parentNode = getItem(parent);
// Q_ASSERT(parentNode);
int count;
stream >> count;
if (row == -1) {
// valid index means: drop onto item. I chose that this should insert
// a child item, because this is the only way to create the first child
of an item...
// This explains why Qt calls it parent: unless you just support
replacing, this
// is really the future parent of the dropped items.
if (parent.isValid())
row = 0;
else
// invalid index means: append at bottom, after last toplevel
row = rowCount(parent);
}
//qDebug() << "The row" << row << parentNode->data().GetName().c_str() ;
for (int i = 0; i < count; ++i) {
// Decode data from the QMimeData
qlonglong nodePtr;
stream >> nodePtr;
TreeItem *node = reinterpret_cast<TreeItem *>(nodePtr);
// Adjust destination row for the case of moving an item
// within the same parent, to a position further down.
// Its own removal will reduce the final row number by one.
if (node->row() < row && parentNode == node->parent())
--row;
// Remove from old position
// qDebug() << "The remove item " << node->data().GetName().c_str();
removeItem(node);
// Insert at new position
//qDebug() << "Inserting into" << parent << row;
beginInsertRows(parent, row, row);
parentNode->insertChild(row, node);
endInsertRows();
++row;
}
return true;
}
void TreeModel::removeItem(TreeItem *node)
{
const int row = node->row();
QModelIndex idx = createIndex(row, 0, node);
TreeItem* itm = getItem(idx);
beginRemoveRows(idx.parent(), row, row);
node->parent()->removeChild(row);
endRemoveRows();
}
Qt::DropActions TreeModel::supportedDropActions() const
{
return Qt::MoveAction;
}
Qt::DropActions TreeModel::supportedDragActions() const
{
return Qt::MoveAction;
}
void TreeModel::setupModelData(const QStringList &lines, TreeItem *parent)
{
QList<TreeItem*> parents;
QList<int> indentations;
parents << parent;
indentations << 0;
int number = 0;
while (number < lines.count()) {
int position = 0;
while (position < lines[number].length()) {
if (lines[number].mid(position, 1) != " ")
break;
position++;
}
QString lineData = lines[number].mid(position).trimmed();
if (!lineData.isEmpty()) {
// Read the column data from the rest of the line.
QStringList columnStrings = lineData.split("t", QString::SkipEmptyParts);
QList<QVariant> columnData;
for (int column = 0; column < columnStrings.count(); ++column)
columnData << columnStrings[column];
if (position > indentations.last()) {
// The last child of the current parent is now the new parent
// unless the current parent has no children.
if (parents.last()->childCount() > 0) {
parents << parents.last()->child(parents.last()->childCount() - 1);
indentations << position;
}
}
else {
while (position < indentations.last() && parents.count() > 0) {
parents.pop_back();
indentations.pop_back();
}
}
Container c;
// Append a new node to the current parent's list of children.
parents.last()->appendChild(new TreeItem(&c, parents.last()));
}
++number;
}
}
TreeItem *TreeModel::getRoot()
{
return rootItem;
}
childItems.removeOne(itm);
和childItems.removeAt(row);
只是从QList<TreeItem*> childItems;
中删除TreeItem *
,这样就不会释放内存。
您应该显式调用delete
,一旦它们被删除,例如您对delete childItems.takeAt(position);
所做的那样。