2010-09-16 122 views
4

我正在使用QSortFilterProxyModel来过滤来自QAbstractListModel的结果。但是,我想返回原始模型中不存在的第一个条目,即它是某种人造的。QSortFilterProxyModel返回虚假行

这是我到目前为止有:

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的这个人造元素,我在那里有点失落。

任何线索?到目前为止我找不到任何相关的代码示例...谢谢!

+0

我不确定QSortFilterProxyModel是最好的地方尝试做到这一点。操作术语是_sort_和_filter_。我认为在定制模型中这样做会更好。 – 2010-09-16 21:26:51

回答

1

我这样做,只是在工作,所以我不能给你很多代码。我可以给你想要做什么的一般想法。

如果您将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

我也走了这条路,但是我有点迷路了mapFrom/mapTo函数:-S即使你无法显示代码,你是否可以添加更多细节?总体思路应该足够了:-)谢谢! – saghul 2010-09-17 16:50:23

+1

非常感谢! – saghul 2010-09-18 11:11:02

2

因为我有些吃力本证的实现过程,由于我找不到在整个网络的任何其他示例代码,我张贴此样本实现。

我希望这也能帮助其他人...

/** 
** 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(); 
} 

问候 斯文

0

我有同样的问题最近,有很多的家长烦恼与源模型马平。

我的版本必须处理左侧的虚拟列,一些链接到动作,可能还有一个是复选框。

希望这可以帮助别人太:)

然而,一记聪明人,我一个子类QSortFilterProxyModel,并通过这样做,我似乎失去对排序使用的能力。我想这是因为我重写了索引/数据方法。如果我碰巧改为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(); 

}