如何制作透明代理模型: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?的主要内容,如果未能解决你的问题,请参考以下文章

什么是透明代理

如何在 Remoting 中创建透明代理

透明代理

如何利用代理知识去提升一个网站的流量

squid 透明代理配置

如何制作透明文字? [复制]