特典——Model的排序與篩選

代碼:

demo5

model的排序苟翻?

我們?cè)谶\(yùn)行demo4的時(shí)候發(fā)現(xiàn)韵卤,這些文件的排列是雜亂的,如果我們要讓他們變得有序該怎么辦呢崇猫?

最簡(jiǎn)單直接的想法是沈条,每次model改變的時(shí)候,我們對(duì)數(shù)據(jù)進(jìn)行重新排序诅炉,但是這對(duì)于需要多種排序方式或者需要提供正向反向排序的視圖來說蜡歹,設(shè)計(jì)這樣一個(gè)model是困難的。

model的篩選涕烧?

如果我們不想讓隱藏的文件顯示在我們的view中月而,該怎么辦呢?

最簡(jiǎn)單直接的想法是议纯,每次篩選的時(shí)候父款,我們需要從數(shù)據(jù)中剔除不符合條件的數(shù)據(jù),但是這種方式會(huì)對(duì)數(shù)據(jù)造成損失瞻凤,對(duì)于樹狀結(jié)構(gòu)憨攒,實(shí)現(xiàn)剔除也是比較麻煩的。

QSortFilterProxyModel——專為排序和篩選而生的Model

好在qt提供了這樣一個(gè)model解決上面兩個(gè)問題阀参,它就是QSortFilterProxyModel肝集。QSortFilterProxyModel是一種model所以它也可以結(jié)合view使用,但是與一般的model不同的是蛛壳,QSortFilterProxyModel它本身不像其它model一樣和數(shù)據(jù)掛鉤杏瞻,而是和model進(jìn)行綁定。view和model可以通過QSortFilterProxyModel這一個(gè)中介實(shí)現(xiàn)數(shù)據(jù)無損的排序和篩選衙荐,我們下面看看它具體是如何實(shí)現(xiàn)的捞挥。

以demo4中的model為例,我們希望我們的model可以按名稱進(jìn)行排序忧吟,并且文件夾在文件之前树肃,同時(shí)我們不希望顯示隱藏文件。

雖然QSortFilterProxyModel提供了一些默認(rèn)的接口用于排序和篩選瀑罗,但是考慮到我們的model并不那么規(guī)范胸嘴,數(shù)據(jù)也不是特別統(tǒng)一雏掠,我們采用繼承QSortFilterProxyModel并且實(shí)現(xiàn)自定義篩選和排序的形式,自定義QSortFilterProxyModel的篩選和排序劣像,首先要override這兩個(gè)方法:

bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;

注意:這兩個(gè)方法中的index屬于source model乡话,我們?cè)趐roxy model中使用source model的index()方法時(shí),一定要小心耳奕,因?yàn)檫@個(gè)時(shí)候可能index可能無法正常創(chuàng)建绑青,這也是和開發(fā)這的代碼流程相關(guān)的,我們盡量使用parent的internalPointer(并結(jié)合sourceRow)進(jìn)行數(shù)據(jù)的檢索屋群,這樣調(diào)試起來也會(huì)方便一些闸婴。

我們看看它的具體實(shí)現(xiàn):

bool SortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
??? //qDebug()<<sourceParent;
??? //return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);

??? FileNode *node = static_cast<FileNode*>(sourceParent.internalPointer());
??? if (node) {
??????? QString displayName = node->m_children.at(sourceRow)->m_info->displayName;
??????? return !displayName.startsWith(".");
??? } else {
??????? SimpleGVfsTreeModel *model = static_cast<SimpleGVfsTreeModel*>(sourceModel());
??????? QString displayName = model->m_root_node->m_children.at(sourceRow)->m_info->displayName;
??????? return !displayName.startsWith(".");
??? }
}

bool SortFilterProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
??? qDebug()<<"lessThan"<<source_left.column();
??? FileNode *left = static_cast<FileNode*>(source_left.internalPointer());
??? FileNode *right = static_cast<FileNode*>(source_right.internalPointer());
??? switch (sortColumn()) {
??? case 0: {
??????? if (!left->hasChildren() && !right->hasChildren()) {
??????????? return left->m_info->displayName < right->m_info->displayName;
??????? }
??????? if (left->hasChildren() && right->hasChildren()) {
??????????? return left->m_info->displayName < right->m_info->displayName;
??????? }
??????? bool isAscendingOrder = sortOrder()==Qt::AscendingOrder;
??????? if (left->hasChildren()) {
??????????? return isAscendingOrder?true:false;
??????? }
??????? if (right->hasChildren()) {
??????????? return isAscendingOrder?false:true;
??????? }
??????? return left->m_info->displayName < right->m_info->displayName;
??? }
??? default:
??????? return QSortFilterProxyModel::lessThan(source_left, source_right);
??? }
}

我目前只針對(duì)第一列進(jìn)行了排序,大家可以自行完善之后幾列的排序芍躏。

另外邪乍,由于view通過proxy model展示數(shù)據(jù),我們從view中獲取的index是proxy model 的index对竣,如果需要獲取對(duì)應(yīng)source model的index庇楞,我們需要使用proxy model的mapToSource()方法。大家也可以嘗試仿照demo2對(duì)demo5進(jìn)行優(yōu)化否纬。

使用QSortFilterProxyModel需要注意Model設(shè)計(jì)的規(guī)范性

我們?cè)赿emo3中做這樣一個(gè)實(shí)驗(yàn)——將insertRow的row永遠(yuǎn)設(shè)置為0吕晌,你會(huì)發(fā)現(xiàn)view的結(jié)果任然沒有變化。把row永遠(yuǎn)設(shè)為0顯然是不合理的临燃,但是我們?nèi)匀坏玫搅苏_的結(jié)果睛驳,這是因?yàn)樵趍odel中,我們的index位置實(shí)際上已經(jīng)由我們的數(shù)據(jù)結(jié)構(gòu)定死了膜廊,insertRow就變成了一個(gè)觸發(fā)model更新和view重繪的方法柏靶,row這個(gè)參數(shù)自然就失去了它的意義。

然而在proxy model中溃论,如果我們不按照邏輯的進(jìn)行insert/remove,則會(huì)出現(xiàn)問題痘昌,這是因?yàn)閜roxy model在響應(yīng)model index的insert/remove時(shí)钥勋,是按照正常的insert/remove邏輯進(jìn)行的,如果我們的邏輯出現(xiàn)問題辆苔,展示出來的結(jié)果自然也會(huì)有問題算灸。

如果想要使用proxy model,則必須規(guī)范model修改的邏輯驻啤,當(dāng)然你也可以不使用proxy model菲驴,自己處理model的sorting,但是這對(duì)于多類型的sorting是很復(fù)雜的骑冗,對(duì)于開發(fā)者的考驗(yàn)很大赊瞬,而且如果你想要篩選數(shù)據(jù)先煎,則你也必須在model中刪除不符合條件的data,這對(duì)于想要重新進(jìn)行篩選的model來說是比較困難的巧涧,你要么從頭開始薯蝎,要么把原來的數(shù)據(jù)備份一份,再改變的時(shí)候再做一次映射谤绳,不管怎么樣都沒有使用proxy model來的方便占锯。

效率的取舍

QSortFilterProxyModel帶來方便的同時(shí),實(shí)際上也會(huì)帶來效率上的損失缩筛,拿上面的demo舉例消略,我們每次改變model,proxy model會(huì)進(jìn)行大量的重排和篩選操作瞎抛。

為了盡可能的減少上面的問題艺演,我們可以在proxy model進(jìn)行排序或者篩選的同時(shí)對(duì)model的數(shù)據(jù)進(jìn)行同樣的邏輯操作,然而這樣對(duì)于需要快速改變排序方式的view來說也是一個(gè)很大的負(fù)擔(dān)婿失。

不管怎么樣钞艇,使用QSortFilterProxyModel帶來的效率上的問題是不可避免的,我們需要做出取舍豪硅,尤其是在model數(shù)據(jù)過于龐大和復(fù)雜的時(shí)哩照,一點(diǎn)點(diǎn)效率上的問題都會(huì)被無限放大,我們圖方便的做法可能就會(huì)導(dǎo)致用戶體驗(yàn)受到影響了懒浮。

盡可能的發(fā)掘QSortFilterModel的潛力

當(dāng)然在大部分的情況下我更偏向于使用QSortFilterProxyModel進(jìn)行model的排序篩選與數(shù)據(jù)展示飘弧。QSortFilterProxyModel的潛力遠(yuǎn)不止我代碼中所寫的這些,我們甚至可以使用它進(jìn)行我們平時(shí)所認(rèn)為的“搜索功能”砚著,比如按文件名或者日期搜索等等次伶,它其實(shí)上是通過篩選得到的結(jié)果。然而稽穆,我們應(yīng)該能夠發(fā)現(xiàn)冠王,篩選受到了數(shù)據(jù)集,也就是sourceModel的限制舌镶,想要打破這一限制柱彻,我們需要獲取更加完善的數(shù)據(jù)集,而不是僅僅只局限于一個(gè)目錄之下餐胀。如果有時(shí)間哟楷,我會(huì)另外寫一篇關(guān)于如何實(shí)現(xiàn)文件搜索的文章,告訴大家如何綜合運(yùn)用QSortFilterProxyModel和搜索框架否灾。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末卖擅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌惩阶,老刑警劉巖挎狸,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異琳猫,居然都是意外死亡伟叛,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門脐嫂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來统刮,“玉大人,你說我怎么就攤上這事账千〗拿桑” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵匀奏,是天一觀的道長(zhǎng)鞭衩。 經(jīng)常有香客問我,道長(zhǎng)娃善,這世上最難降的妖魔是什么论衍? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮聚磺,結(jié)果婚禮上坯台,老公的妹妹穿的比我還像新娘。我一直安慰自己瘫寝,他們只是感情好蜒蕾,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著焕阿,像睡著了一般咪啡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上暮屡,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天撤摸,我揣著相機(jī)與錄音,去河邊找鬼褒纲。 笑死准夷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的外厂。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼代承,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼汁蝶!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤掖棉,失蹤者是張志新(化名)和其女友劉穎墓律,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體幔亥,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡耻讽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了帕棉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片针肥。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖香伴,靈堂內(nèi)的尸體忽然破棺而出慰枕,到底是詐尸還是另有隱情,我是刑警寧澤即纲,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布具帮,位于F島的核電站,受9級(jí)特大地震影響低斋,放射性物質(zhì)發(fā)生泄漏蜂厅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一膊畴、第九天 我趴在偏房一處隱蔽的房頂上張望掘猿。 院中可真熱鬧,春花似錦巴比、人聲如沸术奖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽采记。三九已至,卻和暖如春政勃,著一層夾襖步出監(jiān)牢的瞬間唧龄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工奸远, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留既棺,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓懒叛,卻偏偏與公主長(zhǎng)得像丸冕,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子薛窥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,090評(píng)論 1 32
  • feisky云計(jì)算胖烛、虛擬化與Linux技術(shù)筆記posts - 1014, comments - 298, trac...
    不排版閱讀 3,827評(píng)論 0 5
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 3,805評(píng)論 0 11
  • 今天又是星期一眼姐,這個(gè)星期上夜班,有時(shí)間接送老大佩番,早上老大6點(diǎn)40起床众旗,吃完飯7點(diǎn)多點(diǎn)就送去學(xué)校,如果要坐校車?yán)洗笮?..
    仲昊惟閱讀 171評(píng)論 1 0
  • 不是不配擁有愛情,是需要改變這種直來直去的交流方式赋秀,多點(diǎn)細(xì)心利朵,多點(diǎn)換位思考,多點(diǎn)點(diǎn)委婉的表達(dá)沃琅。 有些男生和女生聊天...
    思遠(yuǎn)236閱讀 2,178評(píng)論 0 1