如何将 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 并返回一个新的 QModelIndex 如果 QMap 在给定行不包含适当的 QModelIndex 。我会尽快回复你。 嘿——看起来 index() 从未在 data() 之前调用过,到那时 QModelIndex 的内部指针为零:/ @nessup,好的,我也会尝试测试它并发布结果。但我真的不认为地图是必要的。【参考方案2】:

我已经制作了一个 QAbstractListModel,它的模型索引包含一个我处理数据绝对需要的指针。

如果你从错误的需求开始,你最终会得到错误的解决方案:)

list 模型非常简单,因此您只需 QModelIndexrow() 即可唯一地定义索引地址的数据。

所以,给定一个 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 与新行关联?的主要内容,如果未能解决你的问题,请参考以下文章

QModelIndex 与 QStandardItem互转

QModelIndex 与 QStandardItem互转

在 Qt 中如何对 QModelIndex 的直接子索引进行排序

如何将 Spark/Scala RDD 合并/加入到 List 中,以便 RDD 中的每个值与每个 List 项一起获得一个新行

QtQModbusRequest类

QTableView::edit( const QModelIndex &index ) 失败