QTreeView的使用(四)

QTreeView的系类文章如下,可根据熟练程度自行食用
QTreeView的使用(一)
QTreeView的使用(二)
QTreeView的使用(三)
PS.本文主要是依据 QTreeView的使用(二)上的代码改过来的!

写作思路

本片博客主要是解决一些在使用QTreeView中遇到的问题
1、在使用QTreeView中使用doubleClicked信号和改变role == Qt.CheckStateRole对象时候的冲突问题
2、刷新树时,层级的收缩状态没有保存的问题
3、自定义过滤器QSortFilterProxyModel的使用技巧
4、在QTreeView中self.selectedIndexes()的坑

1、在使用QTreeView中使用doubleClicked信号和改变role == Qt.CheckStateRole对象时候的冲突问题

问题描述: 如下图gif所示,在点击左侧checkbox的时候,同时会触发doubleClicked信号,这并不是我们想要的效果,初始关键代码如下:
窗口即数据model关键代码如下,详细请看上前面系列文章

def __init__(self):
	......
	self.treeView.doubleClicked.connect(self.onDoubleClicked)
	.....

def onDoubleClicked(self, index):
    print("onDoubleClicked", index)
    def data(self, index, role):
    ......
        elif role == Qt.CheckStateRole:
            if item.isShow is True:
                return Qt.Checked
            else:
                return Qt.Unchecked
    ......

    def setData(self, index, value, role):
        item = index.internalPointer()
        if role == Qt.CheckStateRole:
           item.isShow = False
           .......
        else:
           item.isShow = True
           .......
        return True

在这里插入图片描述
为了避免上述问题,我们需要在自定义item的时候做一点小手脚

def __init__(self):
	......
	self.isChecking = True
	self.treeView.setItemDelegate(ItemDelegate(self.treeView))
	self.treeView.doubleClicked.connect(self.onDoubleClicked)
	.....

def onDoubleClicked(self, index):
	if self.isChecking is False:
    	print("onDoubleClicked", index)
class ItemDelegate(QItemDelegate):
    def __init__(self, parent):
        QItemDelegate.__init__(self, parent)
        ......
        self.checkDistance = 0
        self.iconWidth = 0

	def drawCheck(self, painter, option, rect, state):
        self.checkDistance = rect.left() - option.rect.left()
        self.iconWidth = rect.width()
        super(ItemDelegate, self).drawCheck(painter, option, rect, state)

    def editorEvent(self, event, model, option, index):
        checkRect = QRect(option.rect.left()+self.checkDistance, option.rect.top(),
                          self.iconWidth, self.iconWidth)
        if checkRect.contains(event.pos()):
            hierarchy.isChecking = True
        else:
            hierarchy.isChecking = False
		.......

变化:
相比起之前,我们设置了代理 “self.treeView.setItemDelegate(ItemDelegate(self.treeView))”,

并且多了一个变量,剩下的就是在 editorEvent这个方法里面判断其是否在CheckBox的Rect内

2、刷新树时,层级的收缩状态没有保存的问题

在这里插入图片描述
每次都需要重新整理之前的收缩状态!十分烦!!!

做一点小手脚:

    def createTree(self):
        self.model = FloderTreeModel(self.data)
        self.proxy.setSourceModel(self.model)
        self.isReload = True
        self.treeView.collapseAll()
        self.isReload = False
        if len(BluePrint.editorView.scene.hierachyItemNameIndexMap.items()) == 0:
            self.treeView.expandAll()
        else:
            for name, data in BluePrint.editorView.scene.expandStateDict.items():
                pos = data[len(data)-1]
                index = self.treeView.model().index(pos[0], pos[1], self.treeView.rootIndex())
                for i in range(len(data)-2, -1, -1):
                    pos = data[i]
                    index = self.treeView.model().index(pos[0], pos[1], index)
                self.treeView.expand(index)
    def onCollapsed(self, index):
        self.treeView.model().data(index, Qt.UserRole).isCollapsed = True
        if self.isReload is False:
            if BluePrint.editorView.scene.expandStateDict.get(self.treeView.model().data(index, Qt.UserRole).itemData[0], False):
                BluePrint.editorView.scene.expandStateDict.pop(self.treeView.model().data(index, Qt.UserRole).itemData[0])

    def onExpanded(self, index):
        self.treeView.model().data(index, Qt.UserRole).isCollapsed = False
        if self.isReload is False:
            tempIndex = index
            itemPosList = [[index.row(), index.column()]]
            while tempIndex.parent().row() != -1 or tempIndex.parent().column() != -1:
                itemPosList.append([tempIndex.parent().row(), tempIndex.parent().column()])
                tempIndex = tempIndex.parent()
            BluePrint.editorView.scene.expandStateDict[self.treeView.model().data(index, Qt.UserRole).itemData[0]] = itemPosList

变化:
树收缩状态变化的时候记录下该节点的这个状态,加载的时候让这个节点重新变成该状态,这个方法很笨,但是却能解决这个问题,并且性能消耗其实也不会很多,除非树的深度及节点十分多(应该会优化的)
在这里插入图片描述

3、自定义过滤器QSortFilterProxyModel的使用技巧

	def __init__(self, parent=None):
		self.treeView = QTreeView()
		self.treeView.setModel(self.proxy)
		self.proxy = SearchFilterProxyModel()
		self.model = QAbstractItemModel(self.data)
        self.proxy.setSourceModel(self.model)
class SearchFilterProxyModel(QSortFilterProxyModel):
    def __init__(self):
        super(SearchFilterProxyModel, self).__init__()

    def filterAcceptsRow(self, row_num, source_parent):
    	model = self.sourceModel()
        source_index = model.index(row_num, 0, source_parent)
        .....
        if "填入你想要的条件":
        	return True

技巧:
1、首先将数据data给SearchFilterProxyModel,SearchFilterProxyModel给SearchFilterProxyModel,最后将SearchFilterProxyModel设置到QTreeView

2、在“filterAcceptsRow”方法中,QSortFilterProxyModel会让返回True的item显示出来,至于最重要的东西,我们可以在自定义model中先赋好值,然后通过“model().data(index, Qt.UserRole)”获取我们想要的值对象,并拿来进行判断

4、在QTreeView中QTreeView.selectedIndexes()的坑

在一次使用 QTreeView.selectedIndexes() 的时候,发现返回的list长度与选中的节点数量不一致,当时的代码如下

class TreeItem(object):

    def __init__(self, data, parent=None, isShow=True):
        self.parentItem = parent
        self.itemData = data
        self.childItems = []
        self.isShow = isShow
        self.isCollapsed = True
	......

    def columnCount(self):
        return len(self.itemData)

    .......

(详细代码往前翻之前的文章!)
之前一直没有发现的坑 这里的columeCount,因为QTreeView实际上他的列数,最多就是1,如果这里返回的值不是1,就会导致在调用 QTreeView.selectedIndexes() 的时候,返回的列表不对,比如返回的是2,那么此时返回的就会是两个item,如下图
在这里插入图片描述
并且,得到的QTreeView.selectedIndexes()就会是原来的两倍!因此在这里应该这么写

class TreeItem(object):

    def __init__(self, data, parent=None, isShow=True):
        self.parentItem = parent
        self.itemData = data
        self.childItems = []
        self.isShow = isShow
        self.isCollapsed = True
	......

    def columnCount(self):
        return 1

    .......

当然了,如果真的有需要两行,最好的建议是使用QTreeWidget这个类去继承

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值