QSortFilterProxyModel, возвращающий искусственную строку - PullRequest
4 голосов
/ 16 сентября 2010

Я использую QSortFilterProxyModel для фильтрации результатов из QAbstractListModel. Однако я хотел бы вернуть первую запись, которой нет в исходной модели, то есть она как-то искусственная.

Это то, что я имею до сих пор:

class ActivedAccountModel(QSortFilterProxyModel):                                                                                                                                  
    def __init__(self, model, parent=None):
        super(ActiveAccountModel, self).__init__(parent)
        self.setSourceModel(model)
        self.setDynamicSortFilter(True)

    def data(self, index, role=Qt.DisplayRole):
        account_info = super(ActiveAccountModel, self).data(index, Qt.UserRole).toPyObject()
        if role == Qt.DisplayRole:
            return account_info.name
        elif role == Qt.UserRole:
            return account_info
        return None

    def filterAcceptsRow(self, source_row, source_parent):
        source_model = self.sourceModel()
        source_index = source_model.index(source_row, 0, source_parent)
        account_info = source_model.data(source_index, Qt.UserRole)
        return isinstance(account_info.account, Account) and account_info.account.enabled

Это вернет список в виде:

Account 1
Account 2
...

Id 'хотел бы вернуть дополнительный элемент в начале возвращенного списка f элементов:

Extra Element
Account 1
Account 2
...

Я попытался переопределить rowCount, чтобы вернуть реальное rowCount () + 1, но каким-то образом мне нужно переместить все элементы, чтобы вернуть этот искусственный элемент с индексом 0, и я Я немного потерян там.

Есть подсказка? Пока я не смог найти связанный пример кода ... Спасибо!

Ответы [ 3 ]

3 голосов
/ 26 марта 2015

Поскольку я немного боролся с реализацией этого и потому что я не мог найти какой-либо другой пример кода во всей сети, я публикую этот пример реализации.

Надеюсь, это поможет и другим людям ...

/**
 ** Written by Sven Anders (ANDURAS AG). Public domain code.
 **/

#include <QDebug>
#include <QBrush>
#include <QFont>
#include <QSortFilterProxyModel>

/** Definition **/

class ProxyModelNoneEntry : public QSortFilterProxyModel
{
   Q_OBJECT
 public:
  ProxyModelNoneEntry(QString _entry_text = tr("(None)"), QObject *parent=0);
  int rowCount(const QModelIndex &parent = QModelIndex()) const;
  /* lessThan() is not necessary for this model to work, but can be
     implemented in a derived class if a custom sorting method is required. */
  // bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
  QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
  QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
  QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
  Qt::ItemFlags flags(const QModelIndex &index) const;
  QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
  QModelIndex parent(const QModelIndex &child) const;

 private:
  QString entry_text;
};

/** Implementation **/

ProxyModelNoneEntry::ProxyModelNoneEntry(QString _entry_text, QObject *parent) : QSortFilterProxyModel(parent)
{
  entry_text = _entry_text;
}

int ProxyModelNoneEntry::rowCount(const QModelIndex &parent) const
{
  Q_UNUSED(parent)
  return QSortFilterProxyModel::rowCount()+1;
}

QModelIndex ProxyModelNoneEntry::mapFromSource(const QModelIndex &sourceIndex) const
{
  if (!sourceIndex.isValid()) return QModelIndex();
  else if (sourceIndex.parent().isValid()) return QModelIndex();
  return createIndex(sourceIndex.row()+1, sourceIndex.column());
}

QModelIndex ProxyModelNoneEntry::mapToSource(const QModelIndex &proxyIndex) const
{
  if (!proxyIndex.isValid()) return QModelIndex();
  else if (proxyIndex.row() == 0) return QModelIndex();
  return sourceModel()->index(proxyIndex.row()-1, proxyIndex.column());
}

QVariant ProxyModelNoneEntry::data(const QModelIndex &index, int role) const
{
  if (!index.isValid()) return QVariant();

  if (index.row() == 0)
  {
    if (role == Qt::DisplayRole)
      return entry_text;
    else if (role == Qt::DecorationRole)
      return QVariant();
    else if (role == Qt::FontRole)
    { QFont font; font.setItalic(true); return font; }
    else
      return QVariant();
  }
  return QSortFilterProxyModel::data(createIndex(index.row(),index.column()), role);
}

Qt::ItemFlags ProxyModelNoneEntry::flags(const QModelIndex &index) const
{
  if (!index.isValid()) return Qt::NoItemFlags;
  if (index.row() == 0) return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
  return QSortFilterProxyModel::flags(createIndex(index.row(),index.column()));
}

QModelIndex ProxyModelNoneEntry::index(int row, int column, const QModelIndex &parent) const
{
  if (row > rowCount()) return QModelIndex();
  return createIndex(row, column);
}

QModelIndex ProxyModelNoneEntry::parent(const QModelIndex &child) const
{
  Q_UNUSED(child)
  return QModelIndex();
}

С уважением, Свен

2 голосов
/ 17 сентября 2010

Я сделал это, только на работе, поэтому я не могу дать вам много кода. Я могу дать вам общее представление о том, что делать.

Это работает лучше, если вы подкласс QAbstractProxyModel , который предназначен для общих манипуляций, а не сортировки или фильтрации. Вы захотите переопределить rowCount, а также должны переопределить columnCount (хотя это должно просто вернуть информацию из исходной модели). Вам нужно будет переопределить функцию данных и вернуть свои собственные данные для первой строки или еще раз вызвать исходную модель.

Вы захотите переопределить функции mapFromSource и mapToSource, чтобы разрешить переключение между модельными индексами прокси и исходными модельными индексами.

Чтобы сделать надежную реализацию, вам нужно будет создать несколько слотов и подключиться к сигналам исходной модели для изменения данных, сброса модели и строк / столбцов, которые будут вставлены / удалены. Затем вы должны излучать свои собственные сигналы, должным образом адаптируя их для учета вашего дополнительного ряда.

В нашем классе мы сделали настраиваемый текст для первой строки, чтобы мы могли использовать одну и ту же модель прокси в разных ситуациях. Это стоит изучить для вашего, так как это добавляет минимальных усилий.

Редактировать

За прокомментированный запрос, грубый взгляд на mapToSource и mapFromSource. Это примерно то, о чем вам нужно подумать.

// Remember that this maps from the proxy's index to the source's index, 
// which is invalid for the extra row the proxy adds.
mapToSource( proxy_index ):
    if proxy_index isn't valid:
        return invalid QModelIndex
    else if proxy_index is for the first row:
        return invalid QModelIndex
    else
        return source model index for (proxy_index.row - 1, proxy_index.column)

mapFromSource( source_index ):
    if source_index isn't valid:
        return invalid QModelIndex
    else if source_index has a parent:
        // This would occur if you are adding an extra top-level 
        // row onto a tree model.
        // You would need to decide how to handle that condition
        return invalid QModelIndex
    else
        return proxy model index for (source_index.row + 1, source_index.column)
0 голосов
/ 01 апреля 2015

У меня недавно была такая же проблема, и у меня много проблем с родителями и с сопоставлением с исходной моделью.

Моя версия должна обрабатывать виртуальные столбцы слева, некоторые из них связаны с действиями, ивозможно тот, который является флажком.

Надеюсь, это кому-то тоже поможет :)

Тем не менее, примечание для мудрых, я делю QSortFilterProxyModel на подклассы, и, таким образом, я теряю возможность использовать sortЯ думаю, это потому, что я переопределяю методы индекса / данных.Если вместо этого я получу подкласс QIdentityProxyModel, а затем добавлю QSortFilterProxyModel, я вместо этого потеряю возможность отмечать / снимать флажок моего флажка ... даже если для флагов установлено значение Qt :: ItemIsEnabled |Qt :: ItemIsUserCheckable |Qt :: ItemIsEditable ... хитрый кадр:)

QModelIndex GenericProxy::mapToSource(const QModelIndex & proxy) const {
  if(not proxy.isValid())
    return QModelIndex();

  if((action || checkbox)) {
    int column = proxy.column() - addedCount();
    if(column < 0) // this index is local.
      return QModelIndex();

    QModelIndex idx = sourceModel()->index(proxy.row(), column, mapToSource(proxy.parent()));
    return idx ;
  }

  QModelIndex idx = sourceModel()->index(proxy.row(), proxy.column(), mapToSource(proxy.parent()));
  return idx; 
}

QModelIndex GenericProxy::mapFromSource(const QModelIndex & source) const {
  if(not source.isValid()) 
    return QModelIndex();


  if((action || checkbox)) {
    // simply add appropriate informations ..
    int column = source.column() + addedCount();
    QModelIndex idx = index(source.row(), column, mapFromSource(source.parent()));
    return idx; 
  }
  QModelIndex idx = index(source.row(), source.column(), mapFromSource(source.parent()));
  return idx; 
}

GenericItem * GenericProxy::convert(const QModelIndex & idx) const {
  if(idx.isValid())
    return  _convert(index(idx.row(), firstRealColumn(), idx.parent()));
  else
    return _convert(idx);
}

// _convert doesn't take care of index not really at the rightplace_ness :)
GenericItem * GenericProxy::_convert(const QModelIndex & index) const {
  if(not index.isValid())
    return dynamic_cast<GenericModel *>(sourceModel())->convert(QModelIndex());

  return static_cast<GenericItem*>(index.internalPointer());
}
QModelIndex GenericProxy::parent(const QModelIndex & item) const {
  if(not item.isValid())
    return QModelIndex();

  GenericItem * child = _convert(item);
  if(!child)
    return QModelIndex();
  GenericItem * parent = child->parentItem();
  if(parent == _convert(QModelIndex()))
    return QModelIndex();

  int column = addedCount();
  return sourceModel()->parent(mapToSource(createIndex(item.row(), column, parent )));
}

QModelIndex GenericProxy::index(int row, int column, const QModelIndex & parent) const {
  if( not hasIndex(row,column,parent))
    return QModelIndex();

  GenericItem * pitem = convert(parent);
  GenericItem * pchild = pitem->child(row);

  if(pchild)
    return createIndex(row, column, pchild);
  else
    return QModelIndex();

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...