一、概述
QTreeView行列的插入与删除,若使用QTreeView+QStandardItemModel方式,或者QTreeWidget方式实现的话,直接调用相应的方法就行了。而采用QTreeView+自定义model方式的话,需要我们自己实现数据的插入与删除,故在本节中,我们主要对此方式进行说明。
前面已经对如何实现自定义model,进行了说明,所以对这部分不再赘述。
行与列的插入或删除,比较类似,所以我们只对行操作进行说明,列操作可参考行操作实现。
二、实现插入行
我们重写QAbstractItemModel类insertRows()函数,使用beginInsertRows(),endInsertRows()对实际数据插入操作进行包围,类似于告知View插入开始与结束。
bool TreeModel::insertRows(int row, int count, const QModelIndex &parent)
{
TreeItem *parentItem = itemFromIndex(parent);
beginInsertRows(parent, row, row + count - 1);
for (int i = 0; i < count; i++)
{
TreeItem* item = new TreeItem(parentItem);
parentItem->insertChild(row + i, item);
// 填充item数据
if (parentItem->getType() == TreeItem::PROVINCE)
{
TreeItem::fillPersonData(item,
QString("new name%1").arg(i),
"man",
25,
"123456789");
}
else if (parentItem->getType() == TreeItem::UNKNOWN) // root
{
TreeItem::fillProvinceData(item, QString("new Province%1").arg(i));
}
}
endInsertRows();
return true;
}
beginInsertRows的参数,分别是父节点索引,插入点的行号,结束插入的行号。具体含义,下面的qt帮助截图,可以查看。
void beginInsertRows(const QModelIndex &parent, int first, int last);
另外,需要调用到的几个函数,我们在TreeItem中进行定义
void TreeItem::insertChild(int row, TreeItem* item)
{
_children.insert(row, item);
}
void TreeItem::fillPersonData(TreeItem *item, const QString& name, const QString& sex, int age, const QString& phone)
{
Person* per = new Person();
per->name = name;
per->sex = sex;
per->age = age;
per->phone = phone;
item->setPtr(per); // 保存数据指针
item->setType(TreeItem::PERSON); // 设置节点类型为PERSON
}
void TreeItem::fillProvinceData(TreeItem *item, const QString &name)
{
Province* pro = new Province();
pro->name = name;
item->setPtr(pro); // 保存数据指针
item->setType(TreeItem::PROVINCE); // 设置节点类型为PROVINCE
}
然后,我们在View的右键菜单槽函数中,调用model插入行
void MainWindow::onActionInsert()
{
QModelIndex index = treeView->currentIndex();
if(index.isValid())
{
treeView->model()->insertRow(index.row(), index.parent());
}
}
小贴士:
此处调用的insertRow(),与TreeModel中重写的insertRows(),有何关联?请看下面实现:
inline bool QAbstractItemModel::insertRow(int arow, const >QModelIndex &aparent) { return insertRows(arow, 1, aparent); }
调用insertRow()会自动调用我们重写的insertRows()。
到此,我们实现了插入行。
三、实现删除行
接下来,实现删除行,就更简单了。
类比于插入行,我们也重写QAbstractItemModel类removeRows()函数,使用beginRemoveRows(),endRemoveRows()对实际数据删除操作进行包围,类似于告知View删除开始与结束。
bool TreeModel::removeRows(int row, int count, const QModelIndex &parent)
{
TreeItem *parentItem = itemFromIndex(parent);
beginRemoveRows(parent, row, row + count - 1);
for (int i = 0; i < count; i++)
{
parentItem->removeChild(row);
}
endRemoveRows();
return true;
}
然后,我们在TreeItem中定义删除行函数
void TreeItem::removeChild(int row)
{
TreeItem *item = _children.at(row);
delete item;
_children.removeAt(row);
}
然后,我们在View的右键菜单槽函数中,调用model删除行
void MainWindow::onActionRemove()
{
QModelIndex index = treeView->currentIndex();
if(index.isValid())
{
treeView->model()->removeRow(index.row(), index.parent());
}
}
removeRow()与removeRows()的关系,与上文中小贴士提到的insertRow()与insertRows()关系雷同,不再赘述。
到此,我们实现了删除行。
四、结束
运行效果: