一、Qt中的樹
平時我們經常使用樹的結構來組織和展示數據,比如文件系統等——
在Qt中,我們可以使用Qt提供的便捷的QTreeWidget類,利用該類的接口,輕松地將已有數據顯示在樹中。
除此之外,還可以使用QTreeView,設置它的數據模型,比如QStandardItemModel,我們可以根據自己需要實現更多功能,尤其是在做數據同步的時候特別方便。
二、結點的搜索
在實際的應用中,我們可能需要進行結點的搜索,也就是根據關鍵字過濾出匹配的項,隱藏不匹配的項。
根據我的經驗,一般是在界面中樹的上面放一個搜索輸入框。可以根據輸入內容精確匹配,也可以根據輸入的首字母匹配結點中的漢字。
其實這就是一個樹的遍歷的問題,遍歷的方式可以使用遞歸。
一般搜索方式有兩種:精確搜索和模糊搜索。下面我分兩部分說明,假設樹中節點文字有漢字、英文、數字。
精確搜索
搜索框中輸入漢字時使用精確搜索,我所設計的並不是嚴格意義上的精確搜索。
比如對於文本“東京不太熱Miao”,輸入“京”、“太熱”、“不太熱mi”等關鍵字都能搜到,但是如果輸入“京東”那就不匹配了。
模糊搜索
模糊搜索也就是拼音搜索,輸入漢字的拼音首字母就能搜到它,比如對於“東京不太熱Miao”,輸入“djbtr”、“btr”、“trm”、“trM”等關鍵字都能搜到。
我給拼音首字母搜索加了點功能,就是輸入全拼時也能搜索,但必須從第一個漢字的拼音開始,比如“dongjingb”匹配,但是“jingbutaire”就不匹配了。
三、功能實現
如何區分精確搜索和模糊搜索
搜索框中的輸入全部是英文字母或數字時,使用模糊搜索;否則,如果有漢字,則使用精確搜索。
搜索方式
因為樹有很多級,所以需要使用遞歸遍歷所有節點。將每個節點上的文本與你輸入的關鍵字進行比較,如果匹配,則顯示該節點、它的所有父節點、它的所有子節點,如果不匹配,繼續遍歷其子節點,循環往復,如果找不到匹配,則將其隱藏。
四、難點
樹的搜索很簡單,然而將漢字轉為拼音很麻煩,雖然網上很多很多實現,但都存在缺點。很大一部分是先將漢字轉為ascii,然后獲得其拼音的ascii,繼而得到拼音和首字母。這種方式的缺點是很多生僻字以及部分常見字搜不出來,但對於一般樹的搜索已經夠用了。另一種方式是窮舉,將所有可能的情況都列舉出來,但是這樣做要列舉很多很多情況,占的空間多,而且查詢效率也很低。
五、程序優化
我實現樹的搜索是在一位同事的基礎上修改的,他是這樣實現的:每次搜索框發生改變,都將之前的樹清空,然后重新建立樹,如果樹節點中保存了一些數據,它們將會丟失,或者你需要大費周折才能將數據恢復。
我將節點的增刪,修改成了節點的隱藏顯示。
然后對樹的搜索進行了封裝,最后提供了一個靜態函數static void SearchItem(QTreeWidget *, const QString &);
只需傳2個參數,一個是你所需要搜索的樹,另一個是搜索的關鍵字,就能對樹進行搜索了。
不多說了,分享我所實現類的頭文件部分源碼——
class TreeSearch { public: TreeSearch(); ~TreeSearch(); static void SearchItem(QTreeWidget *, const QString &);//搜索函數 private: static void FuzzySearch(QString &); //模糊搜索 static void FuzzySearchChildren(QTreeWidgetItem *, QString &); //模糊搜索子節點(遞歸) static void PreciseSearch(const QString &); //精確搜索 static void PreciseSearchChildren(QTreeWidgetItem *, const QString &);//精確搜索子節點(遞歸) static void ShowTotalItem(); //顯示所有節點 static void ShowTotalChildrenItem(QTreeWidgetItem *); //顯示所有子節點(遞歸) static void ShowTotalParentItem(QTreeWidgetItem *); //設置所有父節點可顯示(遞歸) static void GetPinYin(const QString &, QString &strInitial, QString &strQuanPin); //將漢字轉為拼音(首字母以及全拼) static void GetWString(const std::string &, std::wstring &wStrOut);//將string轉為wstring private: static QTreeWidget *m_pCurTreeWidget; //當前的樹 };