• 18267阅读
  • 1回复

QModelIndex::internalPointer的意义? [复制链接]

上一主题 下一主题
离线wvins
 
只看楼主 倒序阅读 楼主  发表于: 2009-03-17
— 本帖被 XChinux 从 General Qt Programming 移动到本区(2011-01-02) —
我以为自己对于Qt的MVC模式的认识已经足够清晰了,刚遇到的这个问题把我的信心打击的荡然无存,还希望各位高手继续指点!


==================================
现在我把我对问题的解决方案写下来,顺便总结一下经验认识,希望各位高手指正。

首先,
我们知道对于自己继承的QAbstractItemModel时需要实现index()方法。我的实现如下:
QModelIndex ListModel::index(int row, int column, const QModelIndex &parent) const
{
 if (!parent.isValid())
  return createIndex(row, column, (*rssItems)[row]);
 return QModelIndex();
}
注意标红的语句,其中最后一个参数(*rssItems)[row]是ListItem 的指针。
而这也就是QModelIndex::internalPointer()的无类型指针的来源。
--------------------
在我们使用QModelIndex时应该是能够通过internalPointer()来访问他的对象的。

但是,
通常情况下,我们需要对QAbstractItemModel中的数据进行过滤,也就是QSortFilterProxyModel类所做的事了。
实现filterAcceptsRow()方法和lessThan()方法。

最后,
我需要实现双击打开行为,这就需要编写一个slot处理signal了,也就是QTableView的doubleClicked(const QModelIndex &index)信号。
我查看了一下源代码,这里的QModelIndex实际上传递的是QPersistentModelIndex,所以不用为他的持久化担心。
但问题出在QTableView的setModel方法实际上设置的Model是代理Model(也就是QSortFilterProxyModel),而不是实际持有数据的Model(也就是QAbstractItemModel)。这个QModelIndex的internalPointer有了它自己内在的意义,就不是我们想象的对象了(如这里的ListItem*)。

下面摘抄一段Qt Document中的原话:
QModelIndex QAbstractItemModel::createIndex ( int row, int column, void * ptr = 0 ) const [protected]

Creates a model index for the given row and column with the internal pointer ptr.

Note that when you are using a QSortFilterProxyModel its indexes have their own internal pointer. It is not advisable to access the internal pointer in the index outside of the model. Use the data() function instead.

This function provides a consistent interface that model subclasses must use to create model indexes.
换言之,QModelIndex在这个地方internalPointer()的意义已经改变了,
所幸他的row()和column()并没有改变。。。

所以,
我最终Bug修正前后的代码如下。
修正前:
void FrameRSSItems::onDoubleClick(const QModelIndex & index)
{
 emit selectionChanged(index.data(Qt::UserRole + 1).toString());
 ListItem *item= static_cast<ListItem*>(index.internalPointer());
 //这里的index.internalPointer()实际上不是ListItem*,而是QSortFilterProxyModel内部维护的指针
 QString str = item->caption();
 qDebug()<<str;
}
修正后:
void FrameRSSItems::onDoubleClick(const QModelIndex & index)
{
 emit selectionChanged(index.data(Qt::UserRole + 1).toString());
 (*rssItems)[index.row()]->setReaded(true);
 //通过row()直接访问原始数据解决问题
 rssModel->refresh();
}


离线80437
只看该作者 1楼 发表于: 2010-04-16
这里的index实际上是ProxyModel类的index, 只要把它映射到Source model的index还是可以访问internalPointer()的,
所以, 我觉得以下也是可以的:

void FrameRSSItems::onDoubleClick(const QModelIndex & index)
{
emit selectionChanged(index.data(Qt::UserRole + 1).toString());

QModelndex sourceindex = proxymodel->mapToSource(index);
ListItem *item= static_cast<ListItem*>(sourceindex.internalPointer());
item->setReaded(true);
...
}
快速回复
限100 字节
 
上一个 下一个