如何制作透明代理模型:QAbstractProxyModel?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何制作透明代理模型:QAbstractProxyModel?相关的知识,希望对你有一定的参考价值。
由于我只应对模型进行少许修改,因此透明代理将是最佳起点。此代理将插入到模型链中。
制作代理模型的最简洁方法是什么,在两个方向上源和目标模型之间的每一件事都没有改变?
是否有任何琐碎的index()
,mapToSource()
,mapFromSource()
,...使用sourceModel()
翻译?
我需要扩展的是data()
角色和flags()
。
我知道这应该很容易制作,但我不想让它变得多么复杂,并且通过实践来学习。
谢谢你的时间。
答案
如果您使用的是Qt 4.8或更高版本,您可以使用QIdentityProxyModel,它完全相同:它直接映射源模型而不更改结构,因此您可以重新实现data()
和/或flags()
来修改返回的内容。
在Qt 4.7及更早版本中,最简单的方法应该是重新实现QSortFilterProxyModel而不使用任何排序或过滤,只需覆盖data()
和flags()
。
另一答案
以下是在Qt 4.7下的工作,并显示了保留QAbstractItemModel
语义的最小实现:
// https://github.com/KubaO/stackoverflown/tree/master/questions/transparent-proxy-19835618
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif
class TransparentProxyModel : public QAbstractProxyModel {
Q_OBJECT
struct Helper : QAbstractItemModel {
using QAbstractItemModel::createIndex;
};
struct Op {
enum Kind { AddRow, RemoveRow, AddCol, RemoveCol, MoveRow, MoveCol } kind;
QModelIndex parentSrc;
int first, last;
QModelIndex parentDst;
int index;
bool checkSrc(Kind k, const QModelIndex &i, int f, int l) const {
return kind == k && parentSrc == i && first == f && last == l;
}
bool checkDst(const QModelIndex &i, int n) const {
return parentDst == i && index == n;
}
};
QVector<Op> m_addsRemoves;
QModelIndex createSourceIndex(int r, int c, void *data) const {
return static_cast<Helper *>(sourceModel())->createIndex(r, c, data);
}
Q_SLOT void onDataChanged(const QModelIndex &tl, const QModelIndex &br) {
emit dataChanged(mapFromSource(tl), mapFromSource(br));
}
Q_SLOT void onRowsAboutToBeInserted(const QModelIndex &parent, int first, int last) {
m_addsRemoves.push_back({Op::AddRow, parent, first, last});
beginInsertRows(mapFromSource(parent), first, last);
}
Q_SLOT void onRowsInserted(const QModelIndex &parent, int first, int last) {
Q_ASSERT(!m_addsRemoves.isEmpty());
Q_ASSERT(m_addsRemoves.last().checkSrc(Op::AddRow, parent, first, last));
m_addsRemoves.pop_back();
endInsertRows();
}
Q_SLOT void onRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last) {
m_addsRemoves.push_back({Op::RemoveRow, parent, first, last});
beginRemoveRows(mapFromSource(parent), first, last);
}
Q_SLOT void onRowsRemoved(const QModelIndex &parent, int first, int last) {
Q_ASSERT(!m_addsRemoves.isEmpty());
Q_ASSERT(m_addsRemoves.last().checkSrc(Op::RemoveRow, parent, first, last));
m_addsRemoves.pop_back();
endRemoveRows();
}
Q_SLOT void onColumnsAboutToBeInserted(const QModelIndex &parent, int first,
int last) {
m_addsRemoves.push_back({Op::AddCol, parent, first, last});
beginInsertColumns(parent, first, last);
}
Q_SLOT void onColumnsInserted(const QModelIndex &parent, int first, int last) {
Q_ASSERT(!m_addsRemoves.isEmpty());
Q_ASSERT(m_addsRemoves.last().checkSrc(Op::AddCol, parent, first, last));
m_addsRemoves.pop_back();
endInsertColumns();
}
Q_SLOT void onColumnsAboutToBeRemoved(const QModelIndex &parent, int first, int last) {
m_addsRemoves.push_back({Op::RemoveCol, parent, first, last});
beginRemoveColumns(mapFromSource(parent), first, last);
}
Q_SLOT void onColumnsRemoved(const QModelIndex &parent, int first, int last) {
Q_ASSERT(!m_addsRemoves.isEmpty());
Q_ASSERT(m_addsRemoves.last().checkSrc(Op::RemoveCol, parent, first, last));
m_addsRemoves.pop_back();
endRemoveColumns();
}
Q_SLOT void onRowsAboutToBeMoved(const QModelIndex &srcParent, int start, int end,
const QModelIndex &dstParent, int row) {
m_addsRemoves.push_back({Op::MoveRow, srcParent, start, end, dstParent, row});
beginMoveRows(mapFromSource(srcParent), start, end, mapFromSource(dstParent), row);
}
Q_SLOT void onRowsMoved(const QModelIndex &srcParent, int start, int end,
const QModelIndex &dstParent, int row) {
Q_ASSERT(!m_addsRemoves.isEmpty());
auto const &op = m_addsRemoves.last();
Q_ASSERT(op.checkSrc(Op::MoveRow, srcParent, start, end) &&
op.checkDst(dstParent, row));
m_addsRemoves.pop_back();
endMoveRows();
}
Q_SLOT void onColumnsAboutToBeMoved(const QModelIndex &srcParent, int start, int end,
const QModelIndex &dstParent, int col) {
m_addsRemoves.push_back({Op::MoveCol, srcParent, start, end, dstParent, col});
beginMoveColumns(mapFromSource(srcParent), start, end, mapFromSource(dstParent),
col);
}
Q_SLOT void onColumnsMoved(const QModelIndex &srcParent, int start, int end,
const QModelIndex &dstParent, int col) {
Q_ASSERT(!m_addsRemoves.isEmpty());
auto const &op = m_addsRemoves.last();
Q_ASSERT(op.checkSrc(Op::MoveRow, srcParent, start, end) &&
op.checkDst(dstParent, col));
m_addsRemoves.pop_back();
endMoveColumns();
}
public:
TransparentProxyModel(QObject *parent = nullptr) : QAbstractProxyModel(parent) {}
QModelIndex mapFromSource(const QModelIndex &src) const override {
if (!src.isValid() || !sourceModel()) return {};
Q_ASSERT(src.model() == sourceModel());
return createIndex(src.row(), src.column(), src.internalPointer());
}
QModelIndex mapToSource(const QModelIndex &prx) const override {
if (!prx.isValid() || !sourceModel()) return {};
Q_ASSERT(prx.model() == this);
return createSourceIndex(prx.row(), prx.column(), prx.internalPointer());
}
QModelIndex index(int row, int column, const QModelIndex &parent) const override {
if (!sourceModel()) return {};
Q_ASSERT(!parent.isValid() || parent.model() == this);
return mapFromSource(sourceModel()->index(row, column, mapToSource(parent)));
}
int rowCount(const QModelIndex &parent) const override {
if (!sourceModel()) return 0;
Q_ASSERT(!parent.isValid() || parent.model() == this);
return sourceModel()->rowCount(mapToSource(parent));
}
int columnCount(const QModelIndex &parent) const override {
if (!sourceModel()) return 0;
Q_ASSERT(!parent.isValid() || parent.model() == this);
return sourceModel()->columnCount(mapToSource(parent));
}
QModelIndex parent(const QModelIndex &child) const override {
if (!child.isValid() || !sourceModel()) return {};
Q_ASSERT(child.model() == this);
return mapFromSource(sourceModel()->parent(mapToSource(child)));
}
void setSourceModel(QAbstractItemModel *model) override {
if (sourceModel()) disconnect(sourceModel(), 0, this, 0);
QAbstractProxyModel::setSourceModel(model);
if (!sourceModel()) return;
connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this,
SLOT(onDataChanged(QModelIndex, QModelIndex)));
connect(model, SIGNAL(headerDataChanged(Qt::Orientation, int, int)), this,
SIGNAL(headerDataChanged(Qt::Orientation, int, int)));
connect(model, SIGNAL(layoutChanged()), this, SIGNAL(layoutChanged()));
connect(model, SIGNAL(layoutAboutToBeChanged()), this,
SIGNAL(layoutAboutToBeChanged()));
connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)), this,
SLOT(onRowsAboutToBeInserted(QModelIndex, int, int)));
connect(model, SIGNAL(rowsInserted(QModelIndex, int, int)), this,
SLOT(onRowsInserted(QModelIndex, int, int)));
connect(model, SIGNAL(rowsAboutToBeRemoved(QModelInde以上是关于如何制作透明代理模型:QAbstractProxyModel?的主要内容,如果未能解决你的问题,请参考以下文章