2010-09-16 123 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(); 

}