如何将 QModelIndex 与新行关联?
Posted
技术标签:
【中文标题】如何将 QModelIndex 与新行关联?【英文标题】:How to associate QModelIndex with a new row? 【发布时间】:2011-01-27 04:13:12 【问题描述】:我已经制作了一个QAbstractListModel
,它的模型索引包含一个我处理数据绝对需要的指针。我像这样添加数据:
void PointListModel::addPoint(int frameNumber, QPoint const& pos)
PointItem *pointItem = new PointItem( frameNumber, pos );
QModelIndex newRow = this->createIndex( m_points.count(), 0, pointItem );
qDebug() << newRow.internalPointer();
beginInsertRows( newRow, m_points.count(), m_points.count() );
m_points.insert( m_points.count( ), pointItem );
endInsertRows();
emit pointAdded( pointItem, pos );
直到后来我才意识到beginInsertRows
的参数是要求新行的父模型索引,而不是新行的实际模型索引。
所以,在这个时间点,Qt 让我无法提供QModelIndex
来关联这个特定的行。如何为这个新行创建自己的模型索引?
【问题讨论】:
【参考方案1】:好的,我正在重写我的答案,因为经过一些研究我发现我弄错了。
当您添加新数据时,您不应该做任何特别的事情来创建新索引。您的代码应如下所示:
PointItem *pointItem = new PointItem( frameNumber, pos );
// assume you insert a top level row, having no parent
beginInsertRows( QModelIndex(), m_points.count(), m_points.count() );
m_points.insert( m_points.count( ), pointItem );
endInsertRows();
然后你应该实现 index()
方法,它将根据需要创建索引和 parent()
方法,它将确定某个索引的父级,但是由于你有一个列表模型,它可能应该总是只返回 QModelIndex()
.这里是a good article about creating custom models。
这是一个完整的工作 QAbstractListModel
示例:
class MyModel: public QAbstractListModel
Q_OBJECT
public:
virtual QModelIndex index(int row, int column = 0,
const QModelIndex &parent = QModelIndex()) const;
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
void add(int i);
private:
QList<int> list;
;
void MyModel::add(int i)
beginInsertRows(QModelIndex(), list.size(), list.size());
list.append(i);
endInsertRows();
QModelIndex MyModel::index(int row, int column,
const QModelIndex &parent) const
return hasIndex(row, column, parent) ? createIndex(row, column, (void*)&list[row])
: QModelIndex();
int MyModel::rowCount(const QModelIndex &parent) const
if (parent.isValid())
return 0;
return list.size();
QVariant MyModel::data(const QModelIndex &index,
int role) const
if (!index.isValid())
return QVariant();
if (role != Qt::DisplayRole)
return QVariant();
return QVariant(QString::number(*static_cast<int*>(index.internalPointer())));
【讨论】:
这看起来越来越接近我想要的,但据我了解, index() 函数并不是专门用于创建新行。如何区分新行和现有行之间的 index() 调用?我有一个 QMap 存储我的数据,但 QMap 键目前没有按行号。 @nessup,默认的 QAbstractListModel::index() 实现总是为任何有效坐标调用 createIndex() 所以我想它应该为每个调用创建一个新索引,虽然我也觉得很奇怪.也许索引创建操作被认为是廉价的,所以创建多个重复索引是完全可以的。毕竟,您的实现将与默认实现相同,唯一的区别是您将有意义的数据指针作为数据指针传递给 createIndex() 而不是 NULL(就像默认实现那样)。 好的,谢谢。我将尝试在我的代码中保留一个 QMap我已经制作了一个 QAbstractListModel,它的模型索引包含一个我处理数据绝对需要的指针。
如果你从错误的需求开始,你最终会得到错误的解决方案:)
list 模型非常简单,因此您只需 QModelIndex
的 row()
即可唯一地定义索引地址的数据。
所以,给定一个 QModelIndex
mi
,当你之前这样做时
PointItem * item = static_cast<PointItem*>(mi.internalPointer());
你可以这样做
PointItem * item = plm->pointItemFromIndex(mi);
其中plm
是您的PointListModel
。如果您在需要访问 PointItem
时没有指向它的指针,您可以像这样重构它:
PointItemModel * plm = qobject_cast<PointItemModel*>(mi.model());
// check for !plm here (!mi.isValid() || qobject_cast fails)
反过来,PointListMode::pointItemFromIndex()
会做实际的工作:
PointItem * PointListMode::pointItemFromindex(const QModelIndex &mi) const
return mi.isValid() ? m_points[mi.row()] : 0 ;
这是在 Qt 中使用 QAbstractListModel
时要意识到的最重要的事情:在心理上将 QModelIndex
替换为 int row
,忽略它具有的所有其他内容(无效的 QModelIndex
具有 row() == -1
)。
QAbstractTableModel
也是如此:将QModelIndex
缩减为int row, int column
。忘记其他一切。
您需要完整的QModelIndex
(包括其internalPointer()
或internalId()
)的唯一时间是实现树模型(QAbstractItemModel
)。
【讨论】:
以上是关于如何将 QModelIndex 与新行关联?的主要内容,如果未能解决你的问题,请参考以下文章
在 Qt 中如何对 QModelIndex 的直接子索引进行排序
如何将 Spark/Scala RDD 合并/加入到 List 中,以便 RDD 中的每个值与每个 List 项一起获得一个新行