【发布时间】:2025-12-31 16:05:08
【问题描述】:
我有一个从 QAbstractListModel 子类化的模型,它具有不同的 Listviews,这些 Listviews 使用子类 QSortFilterProxyModel 对每个视图进行过滤。当用户单击排序按钮时,可以对视图中的数据进行排序。
我在 QSortFilterProxyModel 中实现了拖放,以在将数据拖放到新的 Listview 时更改数据的状态。这很好用,但是,手动对列表视图中的项目进行排序会导致所有其他显示相同数据的列表视图也被排序,这不是我想要的。
例如,视图 1 显示所有参与者,视图 2 显示处于活动状态的参与者。当从视图 1 拖动到视图 2 时,参与者变为活动状态。如果我手动对参与者进行排序,那么活跃的参与者的索引也会被排序。但是,如果我使用 proxyModel->sort() 方法自动对它们进行排序,则不会发生这种情况。
如何在不更改源模型索引的情况下手动重新排列代理模型中的数据?
示例代码:
MySortFilterProxyModel::MySortFilterProxyModel(bool active, QObject *parent ) :
QSortFilterProxyModel( parent ),
m_filter( "" ),
m_active(active)
{
setDynamicSortFilter( false );
}
void MySortFilterProxyModel::setFilter( QString filter )
{
m_filter = filter;
invalidateFilter();
}
Qt::ItemFlags MySortFilterProxyModel::flags( const QModelIndex &index ) const
{
if( index.isValid() )
{
return ( QSortFilterProxyModel::flags( index ) | Qt::ItemIsDragEnabled | Qt::ItemIsEditable );
}
return Qt::ItemIsDropEnabled | QSortFilterProxyModel::flags( index );
}
bool MySortFilterProxyModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
{
if( !data->hasFormat( dataModel::dataMimeType() ) )
{
return false;
}
if( action == Qt::IgnoreAction )
{
return true;
}
if( column > 0 )
{
return false;
}
QByteArray encodeData = data->data(dataModel::dataMimeType());
QDataStream stream( &encodeData, QIODevice::ReadOnly );
while( !stream.atEnd() )
{
DataRecord *dr = new DataRecord();
stream >> dr;
dr->setActive( m_active );
// AddData method in the dataModel removes duplicate rows and inserts the data into the correct row.
qobject_cast< DataModel * >( sourceModel() )->addData( fdr, parent.row() );
}
return true;
}
Edit addData() 可能有更好的方法来做到这一点:
void DataModel::addData( DataRecord *dr, int row )
{
int i =0;
for( auto const& itr : m_dataRecords )
{
if( itr->getUniqueID() == dr->getUniqueID() )
{
break;
}
++i;
}
removeRows( i, 1, QModelIndex() );
beginInsertRows( QModelIndex(), row, row );
m_dataRecords.insert( row, dr );
endInsertRows();
}
在 DataModel 中,我还实现了以下方法:
QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override;
bool setData( const QModelIndex & index, const QVariant & value, int role=Qt::EditRole );
bool removeRows( int row, int count, const QModelIndex &parent ) override;
QMimeData *mimeData( const QModelIndexList &indexes ) const override;
QStringList mimeTypes() const override;
int rowCount( const QModelIndex &parent ) const override;
Qt::DropActions supportedDropActions() const override;
【问题讨论】:
-
你能显示
DataModel::addData吗? -
是的,我将其添加到问题中。
-
如果没有
mapToSource()父级,您不能传递parent.row()并确保它有效。 -
好的,但我仍然只是更新 sourceModel 的索引,而不仅仅是代理模型。我想知道是否应该在 ProxyModel 中实现 mimeData 方法并以某种方式跟踪代理过滤的项目,但这对我来说并不明显。
-
不幸的是,如果不查看模型实现,就很难看出问题所在。 QAbstractItemModel 子类化是一个雷区
标签: c++ qt c++11 qt5 qsortfilterproxymodel