PyQt5系列教程(42):TIM模擬(QTreeWidget的使用)3
來自專欄 PyQt5圖形界面編程
好的,我們接上期繼續談。上期我們介紹了如何創建組、如何創建聯繫人,這期我們探討一下在分組上單擊右鍵實現的菜單功能。
分組右鍵菜單代碼介紹
def contextMenuEvent(self, event): hititem = self.treeWidget.currentItem() if hititem: root = hititem.parent() if root is None: pgroupmenu = QMenu(self) pAddgroupAct = QAction(添加分組,self.treeWidget) pRenameAct = QAction(重命名,self.treeWidget) pDeleteAct = QAction(刪除該組,self.treeWidget) pgroupmenu.addAction(pAddgroupAct) pgroupmenu.addAction(pRenameAct) pgroupmenu.addAction(pDeleteAct) pAddgroupAct.triggered.connect(self.addgroup) pRenameAct.triggered.connect(self.renamegroup) if self.treeWidget.itemAbove(hititem) is None: pDeleteAct.setEnabled(False) else: pDeleteAct.triggered.connect(self.deletegroup) pgroupmenu.popup(self.mapToGlobal(event.pos())) ……def addgroup(self): gname, ok = QInputDialog.getText(self,提示信息,請輸入分組名稱) if ok: if len(gname) == 0: QMessageBox.information(self,提示,分組名稱不能為空哦) else: self.creategroup(gname) def renamegroup(self): hitgroup = self.treeWidget.currentItem() gnewname, ok = QInputDialog.getText(self,提示信息,請輸入分組的新名稱) if ok: if len(gnewname) == 0: QMessageBox.information(self,提示,分組名稱不能為空哦) else: hitgroup.setText(0, gnewname) newicon = self.searchicon(hitgroup.text(0)) hitgroup.setIcon(0, newicon) gindex = self.searchgroup(hitgroup) self.grouplist[gindex][groupname] = gnewname self.treeWidget.setCurrentItem(hitgroup.child(0)) def deletegroup(self): hitgroup = self.treeWidget.currentItem() gindex = self.searchgroup(hitgroup) reply = QMessageBox.question(self,警告,確定要刪除這個分組及其聯繫人嗎?, QMessageBox.Yes | QMessageBox.No , QMessageBox.No) if reply == QMessageBox.Yes: self.treeWidget.takeTopLevelItem(gindex) del self.grouplist[gindex] def searchgroup(self, hitgroup): if isinstance(hitgroup,str): for i,g in enumerate(self.grouplist): if g[groupname] == hitgroup: return i else: for i,g in enumerate(self.grouplist): if g[group] == hitgroup: return i
我們重寫了右鍵菜單的函數。
hititem = self.treeWidget.currentItem()
返回樹小部件中的當前項目,這裡可以是分組也可以是聯繫人。
if hititem: root = hititem.parent() if root is None: ...
這裡有一個邏輯關係在這裡面,首先返回的項目必須存在(分組或者聯繫人),有不存在的情況嗎?當然有啊,當我們刪除全部聯繫人的時候,如下圖:
hititem.parent()就是要看看這個項目是否有上一節點,有的話就是聯繫人沒有的話就是分組了。所以我們根據這點來判斷究竟是在分組上單擊右鍵還是在聯繫人上單擊右鍵。
下面就好說了,都是一些常規操作,生成菜單之類的,然後單擊菜單就能調用相應的槽函數,這裡不做講解了,之前的章節都有介紹。具體的槽函數我介紹一下。
def addgroup(self): gname, ok = QInputDialog.getText(self,提示信息,請輸入分組名稱) if ok: if len(gname) == 0: QMessageBox.information(self,提示,分組名稱不能為空哦) else: self.creategroup(gname)
當我們點擊增加分組的時候(如下圖),會提示輸入名稱,名稱不能為空,符合要求的話就創建分組。
QInputDialog的知識點請參見
學點編程吧:PyQt5系列教程(8):標準輸入對話框def renamegroup(self): hitgroup = self.treeWidget.currentItem() gnewname, ok = QInputDialog.getText(self,提示信息,請輸入分組的新名稱) if ok: if len(gnewname) == 0: QMessageBox.information(self,提示,分組名稱不能為空哦) else: hitgroup.setText(0, gnewname) newicon = self.searchicon(hitgroup.text(0)) hitgroup.setIcon(0, newicon) gindex = self.searchgroup(hitgroup) self.grouplist[gindex][groupname] = gnewname self.treeWidget.setCurrentItem(hitgroup.child(0))
這個函數首先要獲取分組對象。然後我們根據新的名稱給這個分組對象設置分組名稱setText()、圖標setIcon(),更新用於存儲數據的列表self.grouplist。這裡提一下self.searchgroup(hitgroup)函數。
def searchgroup(self, hitgroup): if isinstance(hitgroup,str): for i,g in enumerate(self.grouplist): if g[groupname] == hitgroup: return i else: for i,g in enumerate(self.grouplist): if g[group] == hitgroup: return i
這裡我們是可以根據分組的名稱或者對象找到數據存儲列表中相應分組字典的索引並返回。為什麼這樣操作呢?因為我們不僅僅需要知道分組對象和名稱,我們還需要知道其對應的其它屬性,如隱身聯繫人數量等等啊。這些數據本可以從資料庫中直接取出,這裡也是為了簡化知識點,不涉及資料庫知識。
其實在QTreeWidget類中,有函數是涉及找Item的:
findItems(self, str, Union[Qt.MatchFlags, Qt.MatchFlag], column: int = 0)
根據給定文本返回給定列中使用給定標誌的匹配項目列表(因為有可能同名,所以返回是列表)。
因為我覺得該程序中不僅僅涉及分組對象和名稱還有其他屬性,用這個函數不夠用,所有我採用折中的辦法來找。個人觀點,僅供參考。
def renamegroup(self):…… self.treeWidget.setCurrentItem(hitgroup.child(0))
在renamegroup()函數中為什麼還要增加以上這句話呢?設置當前的項目(這裡表示分組中的第一個聯繫人)。
因為我們在程序最前面有這樣一句:
self.treeWidget.currentItemChanged.connect(self.restatistic)
當前項目發生變化的時候,我們自動調用restatistic()函數。話說這個restatistic()又是個什麼玩意?
我們在上一章節的時候說過,在重命名分組、新增分組、新增聯繫人的時候,都會涉及到分組名稱中數量的統計功能,要是在每個功能上都重新把統計功能寫一遍,感覺太過繁瑣,所以還是抽象成一個函數更好一些。這個restatistic()就是針對分組的統計函數。
currentItemChanged()信號發射的時候,會自動傳入兩個參數,當前項目和改變前的項目(QTreeWidgetItem)。
def restatistic(self, item, preitem): if item: fathergroup = item.parent() if fathergroup: self.restatistic_op(fathergroup) else: self.restatistic_op(item) elif preitem.parent().childCount() == 1: lastgroupname = preitem.parent().text(0).split()[0] + 0/0 preitem.parent().setText(0, lastgroupname) self.menuflag = 1def restatistic_op(self, itemorgroup): gindex = self.searchgroup(itemorgroup) totalcount = self.grouplist[gindex][childcount] hidecount = self.grouplist[gindex][childishide] fathergroupname = self.grouplist[gindex][groupname] fathergroupname += + str(totalcount - hidecount) + / + str(totalcount) itemorgroup.setText(0, fathergroupname)
故以上這兩個函數表示分組數量重新統計。
我們首先判斷當前項目(QTreeWidgetItem)究竟是分組還是聯繫人(item.parent()判斷),然後在帶入restatistic_op()進行計算。
如果改變前項目節點的子節點數量為1(改變前分組只有一個人了),我們直接設定這個分組的名稱是這樣的:我的好友 0/0,並將self.menuflag = 1。為什麼要設置為1,我們在批量操作哪裡再說,嘿嘿。( ̄┰ ̄*)
restatistic_op()這個函數很好理解,根據分組對象我們在self.grouplist取到相應的聯繫人數量、隱身聯繫人的數量,然後再設置分組名稱,如 我的好友 8/10。
現在我們再回到刪除分組這個函數。
def deletegroup(self): hitgroup = self.treeWidget.currentItem() gindex = self.searchgroup(hitgroup) reply = QMessageBox.question(self,警告,確定要刪除這個分組及其聯繫人嗎?, QMessageBox.Yes | QMessageBox.No , QMessageBox.No) if reply == QMessageBox.Yes: self.treeWidget.takeTopLevelItem(gindex) del self.grouplist[gindex]
我們確認刪除前彈出對話框,要求用戶確認是否能夠刪除。QMessageBox的知識點請參考:
學點編程吧:PyQt5系列教程(11):今天的消息挺全哦!self.treeWidget.takeTopLevelItem(gindex)
刪除樹中給定索引處的頂級項目並返回它,否則返回0;這裡的分組索引其實和我們在self.grouplist中索引是一致的。當然我們最後也要把在self.grouplist的數據也要刪除,否則就會造成數據不一致啦。
if self.treeWidget.itemAbove(hititem) is None: pDeleteAct.setEnabled(False)else: pDeleteAct.triggered.connect(self.deletegroup)pgroupmenu.popup(self.mapToGlobal(event.pos()))
這裡表示最頂端的分組(它的上面是有沒分組的),pDeleteAct設置為禁用。否則是可以執行的。
pgroupmenu.popup(self.mapToGlobal(event.pos()))
沒有這句話菜單是不會出現的,相關知識點之前已經介紹過了。
最後
ok,今天的介紹就到這裡吧,下期接著更。如果你喜歡本篇文章,請給我點贊
讚賞(推薦)
分享給你的好友們吧!
關注微信公眾號:學點編程吧,你可以學到更多!加油!(? ??_??)? (*?????)
推薦閱讀: