由于我只对模型进行少许修改,因此透明代理将是最佳起点。此代理将插入到模型链中。
制作代理模型最简洁的方法是什么,在两个方向上源和目标模型之间的每一件事都没有改变?
使用index()
是否有任何简单的mapToSource()
,mapFromSource()
,sourceModel()
,...翻译?
我需要扩展的是data()
角色和flags()
。
我知道这应该很容易制作,但我不想让它变得多么复杂,并且通过实践来学习。
Thanx你的时间。
答案 0 :(得分:5)
如果您使用的是Qt 4.8或更高版本,则可以使用QIdentityProxyModel,它完全相同:它直接映射源模型而不更改结构,因此您可以重新实现data()
和/或flags()
修改返回的内容。
在Qt 4.7及更早版本中,最简单的方法是重新实现QSortFilterProxyModel而不使用任何排序或过滤,只需覆盖data()
和flags()
。
答案 1 :(得分:2)
以下内容在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(QModelIndex, int, int)), this,
SLOT(onRowsAboutToBeRemoved(QModelIndex, int, int)));
connect(model, SIGNAL(rowsRemoved(QModelIndex, int, int)), this,
SLOT(onRowsRemoved(QModelIndex, int, int)));
connect(model, SIGNAL(columnsAboutToBeInserted(QModelIndex, int, int)), this,
SLOT(onColumnsAboutToBeInserted(QModelIndex, int, int)));
connect(model, SIGNAL(columnsInserted(QModelIndex, int, int)), this,
SLOT(onColumnsInserted(QModelIndex, int, int)));
connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)), this,
SLOT(onColumnsAboutToBeRemoved(QModelIndex, int, int)));
connect(model, SIGNAL(columnsRemoved(QModelIndex, int, int)), this,
SLOT(onColumnsRemoved(QModelIndex, int, int)));
connect(model, SIGNAL(modelAboutToBeReset()), this, SIGNAL(modelAboutToBeReset()));
connect(model, SIGNAL(modelReset()), this, SIGNAL(modelReset()));
connect(model, SIGNAL(rowsAboutToBeMoved(QModelIndex, int, int, QModelIndex, int)),
this, SLOT(onRowsAboutToBeMoved(QModelIndex, int, int, QModelIndex, int)));
connect(model, SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int)), this,
SLOT(onRowsMoved(QModelIndex, int, int, QModelIndex, int)));
connect(
model, SIGNAL(columnsAboutToBeMoved(QModelIndex, int, int, QModelIndex, int)),
this, SLOT(onColumnsAboutToBeMoved(QModelIndex, int, int, QModelIndex, int)));
connect(model, SIGNAL(columnsMoved(QModelIndex, int, int, QModelIndex, int)), this,
SLOT(onColumnsMoved(QModelIndex, int, int, QModelIndex, int)));
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QFileSystemModel model;
TransparentProxyModel proxy;
proxy.setSourceModel(&model);
QTreeView view;
view.setModel(&proxy);
model.setRootPath(QDir::homePath());
view.setRootIndex(proxy.mapFromSource(model.index(QDir::homePath())));
view.show();
return app.exec();
}
#include "main.moc"
答案 2 :(得分:1)
我已经制定了自己的解决方案。它不会使任何索引发生变化。实际上它不应该。 信号被转移。
如果将此模型插入模型链中,则不应影响模型链。
#ifndef TTRANSPARENTPROXYMODEL_H
#define TTRANSPARENTPROXYMODEL_H
#include <QAbstractProxyModel>
class TTransparentProxyModel :
public QAbstractProxyModel
{
Q_OBJECT
public:
TTransparentProxyModel(QObject *parent = 0);
void setSourceModel(QAbstractItemModel* newSourceModel);
/* QAbstractProxyModel methods */
virtual QModelIndex index( int, int c = 0, const QModelIndex& parent = QModelIndex() ) const;
virtual QModelIndex parent( const QModelIndex &child ) const;
virtual int rowCount( const QModelIndex &idx = QModelIndex() ) const;
virtual int columnCount(const QModelIndex &parent ) const;
virtual QModelIndex mapToSource( const QModelIndex &index ) const;
virtual QModelIndex mapFromSource( const QModelIndex &idx ) const;
};
#endif // TTRANSPARENTPROXYMODEL_H
和cpp文件:
#include "TransparentProxyModel.h"
TTransparentProxyModel::TTransparentProxyModel(QObject *parent)
: QAbstractProxyModel(parent)
{
}
void TTransparentProxyModel::setSourceModel(QAbstractItemModel* newSourceModel)
{
beginResetModel();
if (sourceModel()) {
disconnect(sourceModel(), SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)),
this, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)));
disconnect(sourceModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)),
this, SIGNAL(rowsInserted(const QModelIndex &, int, int)));
disconnect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
this, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)));
disconnect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
this, SIGNAL(rowsRemoved(const QModelIndex &, int, int)));
disconnect(sourceModel(), SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
this, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
disconnect(sourceModel(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
this, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
disconnect(sourceModel(), SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)),
this, SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)));
disconnect(sourceModel(), SIGNAL(columnsInserted(const QModelIndex &, int, int)),
this, SIGNAL(columnsInserted(const QModelIndex &, int, int)));
disconnect(sourceModel(), SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)),
this, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)));
disconnect(sourceModel(), SIGNAL(columnsRemoved(const QModelIndex &, int, int)),
this, SIGNAL(columnsRemoved(const QModelIndex &, int, int)));
disconnect(sourceModel(), SIGNAL(columnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
this, SIGNAL(columnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
disconnect(sourceModel(), SIGNAL(columnsMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
this, SIGNAL(columnsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
disconnect(sourceModel(), SIGNAL(modelAboutToBeReset()),
this, SIGNAL(modelAboutToBeReset()));
disconnect(sourceModel(), SIGNAL(modelReset()),
this, SIGNAL(modelReset()));
disconnect(sourceModel(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
this, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)));
disconnect(sourceModel(), SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
this, SIGNAL(headerDataChanged(Qt::Orientation,int,int)));
disconnect(sourceModel(), SIGNAL(layoutAboutToBeChanged()),
this, SIGNAL(layoutAboutToBeChanged()));
disconnect(sourceModel(), SIGNAL(layoutChanged()),
this, SIGNAL(layoutChanged()));
}
QAbstractProxyModel::setSourceModel(newSourceModel);
if (sourceModel()) {
connect(sourceModel(), SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)),
this, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)));
connect(sourceModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)),
this, SIGNAL(rowsInserted(const QModelIndex &, int, int)));
connect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
this, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)));
connect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
this, SIGNAL(rowsRemoved(const QModelIndex &, int, int)));
connect(sourceModel(), SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
this, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
connect(sourceModel(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
this, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
connect(sourceModel(), SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)),
this, SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)));
connect(sourceModel(), SIGNAL(columnsInserted(const QModelIndex &, int, int)),
this, SIGNAL(columnsInserted(const QModelIndex &, int, int)));
connect(sourceModel(), SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)),
this, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)));
connect(sourceModel(), SIGNAL(columnsRemoved(const QModelIndex &, int, int)),
this, SIGNAL(columnsRemoved(const QModelIndex &, int, int)));
connect(sourceModel(), SIGNAL(columnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
this, SIGNAL(columnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
connect(sourceModel(), SIGNAL(columnsMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
this, SIGNAL(columnsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
connect(sourceModel(), SIGNAL(modelAboutToBeReset()),
this, SIGNAL(modelAboutToBeReset()));
connect(sourceModel(), SIGNAL(modelReset()),
this, SIGNAL(modelReset()));
connect(sourceModel(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
this, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)));
connect(sourceModel(), SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
this, SIGNAL(headerDataChanged(Qt::Orientation,int,int)));
connect(sourceModel(), SIGNAL(layoutAboutToBeChanged()),
this, SIGNAL(layoutAboutToBeChanged()));
connect(sourceModel(), SIGNAL(layoutChanged()),
this, SIGNAL(layoutChanged()));
}
endResetModel();
}
//virtual int rowCount( const QModelIndex &idx = QModelIndex() ) const;
int TTransparentProxyModel::rowCount(const QModelIndex &parent) const
{
if(!sourceModel())
{
return 0;
}
return this->sourceModel()->rowCount(parent);
}
//virtual int columnCount( const QModelIndex &idx ) const;
int TTransparentProxyModel::columnCount(const QModelIndex &parent) const
{
if(!sourceModel())
{
return 0;
}
return this->sourceModel()->columnCount(parent);
}
//virtual QModelIndex index( int, int c = 0, const QModelIndex& parent = QModelIndex() ) const;
QModelIndex TTransparentProxyModel::index(int row, int column, const QModelIndex &parent) const
{
if(!this->sourceModel())
{
return QModelIndex();
}
return this->sourceModel()->index(row,column,parent);
}
//virtual QModelIndex parent( const QModelIndex &idx ) const;
QModelIndex TTransparentProxyModel::parent(const QModelIndex &child) const
{
// TODO: check if this is valid.
QModelIndex mi = mapFromSource(child);
if (mi.isValid())
{
return mi.parent();
}
return QModelIndex();
}
//virtual QModelIndex mapToSource( const QModelIndex &idx ) const;
QModelIndex TTransparentProxyModel::mapToSource(const QModelIndex &index) const
{
if(!this->sourceModel())
{
return QModelIndex();
}
return this->sourceModel()->index(index.row(),index.column());
}
//virtual QModelIndex mapFromSource( const QModelIndex &idx ) const;
QModelIndex TTransparentProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
{
if(sourceIndex.isValid())
if(!this->sourceModel())
{
return QModelIndex();
}
return this->sourceModel()->index(sourceIndex.row(),sourceIndex.column());
}
我试图捕捉来自源的所有信号,并以相同的方式发信号到下一个模型。
唯一的方法,我不确定它是否已正确实施,是parent()
。
我希望这有用。