如何将 QModelIndex 与新行关联?

发布于 2024-10-14 05:00:15 字数 709 浏览 2 评论 0原文

我已经编写了一个 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 的参数要求的是新行的 parent 模型索引,而不是新行的实际索引型号索引。

因此,此时,Qt 无法提供与此特定行关联的 QModelIndex。如何为这个新行创建自己的模型索引?

I've cooked up a QAbstractListModel whose model indexes contain a pointer I absolutely needed in order to process data. I add the data like so:

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 );
}

It was only later that I realized that the argument to beginInsertRows is asking for the parent model index of the new row, not the new row's actual model index.

So, at this point in time, Qt has given me no way of supplying a QModelIndex to associate with this particular row. How do I create my own model index for this new row?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

旧人 2024-10-21 05:00:15

好吧,我正在重写我的答案,因为经过一番研究后我发现我错了。

添加新数据时,您不应该执行任何特殊操作来创建新索引。您的代码应如下所示:

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()。这是一篇关于创建自定义模型的好文章

下面是一个工作 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())));
}

Okay, I'm rewriting my answer as after some research I've found out that I got it wrong.

You shouldn't do anything special to create a new index when you add new data. You code should look like this:

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();

Then you should implement the index() method which will create indexes on demand and the parent() method which will determine the parent of some index, but since you have a list model, it should probably always just return QModelIndex(). Here is a good article about creating custom models.

Here is a complete example of a working 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())));
}
黯然 2024-10-21 05:00:15

我已经编写了一个 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 时要意识到的最重要的事情:在心里用 int row 替换 QModelIndex,忽略它拥有的其他所有内容(无效的 QModelIndex 具有 row() == -1)。

对于QAbstractTableModel也是如此:在心里将QModelIndex减少到int row, int column。忘记其他一切。

唯一需要完整的QModelIndex(包括其internalPointer()internalId())是当您实现树模型时(QAbstractItemModel)。

I've cooked up a QAbstractListModel whose model indexes contain a pointer I absolutely needed in order to process data.

If you start with wrong requirements, you end up with wrong solutions :)

A list model is simple enough so that you don't need more than the QModelIndex's row() to uniquely define the data the index addresses.

So, given a QModelIndex mi, when you before did

PointItem * item = static_cast<PointItem*>(mi.internalPointer());

you can instead do

PointItem * item = plm->pointItemFromIndex(mi);

where plm is your PointListModel. If you don't have a pointer to it lying around when you need to access the PointItem, you can reconstruct it like this:

PointItemModel * plm = qobject_cast<PointItemModel*>(mi.model());
// check for !plm here (!mi.isValid() || qobject_cast fails)

In turn, PointListMode::pointItemFromIndex() would do the actual work:

PointItem * PointListMode::pointItemFromindex(const QModelIndex &mi) const {
    return mi.isValid() ? m_points[mi.row()] : 0 ;
}

This is the most important thing to realize when working with QAbstractListModel in Qt: Mentally replace QModelIndex with int row, ignore everything else it has (an invalid QModelIndex has row() == -1).

Same for QAbstractTableModel: mentally reduce the QModelIndex to int row, int column. Forget everything else.

The only time you need the full QModelIndex (including its internalPointer() or internalId() is when you implement a tree model (QAbstractItemModel).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文