QTreeWidget 插入顶级项时索引不准确显示?

0 投票
2 回答
2761 浏览
提问于 2025-04-15 20:52

我在尝试把一个QTreeWidgetItem插入到特定的位置时遇到了问题。具体来说,我先把树里的所有QTreeWidgetItems都移除,然后根据它们的日期对象进行自定义排序,最后再把它们插回QTreeWidget里。

但是,当我插入这些项时(即使是一个一个插入),它们并没有被放到正确的位置。

下面的代码打印出了:

索引 0: 0

索引 0: 1 索引 1: 0

索引 0: 2 索引 1: 1 索引 2: 0

索引 0: 3 索引 1: 2 索引 2: 0 索引 3: 1

索引 0: 4 索引 1: 2 索引 2: 0 索引 3: 1 索引 4: 3

print 'index 0: ', self.indexOfTopLevelItem(childrenList[0])

self.insertTopLevelItem(0, childrenList[1])

print 'index 0: ', self.indexOfTopLevelItem(childrenList[0]), ' index 1: ',\
    self.indexOfTopLevelItem(childrenList[1])

self.insertTopLevelItem(0, childrenList[2])

print 'index 0: ', self.indexOfTopLevelItem(childrenList[0]), ' index 1: ',\
    self.indexOfTopLevelItem(childrenList[1]), ' index 2: ', \
    self.indexOfTopLevelItem(childrenList[2])

self.insertTopLevelItem(0, childrenList[3])

print 'index 0: ', self.indexOfTopLevelItem(childrenList[0]), ' index 1: ',\
    self.indexOfTopLevelItem(childrenList[1]), ' index 2: ',\
    self.indexOfTopLevelItem(childrenList[2]), 'index 3: ',\
    self.indexOfTopLevelItem(childrenList[3])

self.insertTopLevelItem(0, childrenList[4])

print 'index 0: ', self.indexOfTopLevelItem(childrenList[0]),\
    ' index 1: ', self.indexOfTopLevelItem(childrenList[1]),\
    ' index 2: ', self.indexOfTopLevelItem(childrenList[2]),\
    'index 3: ', self.indexOfTopLevelItem(childrenList[3]),\
    'index 4: ', self.indexOfTopLevelItem(childrenList[4])

2 个回答

2

问题可能出在你代码的其他地方。也许你没有正确地移除那些项目?因为下面的代码是可以正常工作的:

import sys

from PyQt4.QtGui import *
from PyQt4.QtCore import *

app = QApplication(sys.argv)

tree = QTreeWidget()
items = [QTreeWidgetItem(['index %i' % i]) for i in range(5)]

for item in items:
    tree.insertTopLevelItem(0, item)

print 'indexes: '
for item in items:
    print tree.indexOfTopLevelItem(item),

tree.show()

app.exec_()
2

你可以自定义排序,而不需要重新填充树形结构。只需要重载项目的“less”操作符就可以了。注意,QT会根据项目的内容来决定在单元格中绘制什么,大小应该是多少,文本内容是什么。

virtual QVariant data ( int column, int role ) const

当你创建一个项目时,你需要给构造函数提供一个字符串,这个字符串就是项目要显示的内容。这个字符串会被放到数据中(.., QtCore.Qt.EditRole),所以,传递数据给构造函数的等价方式就是用以下方法设置数据:

virtual void setData ( int column, int role, const QVariant & value)

在内部,数据其实就是一个数组,你可以放任何你想要的东西,数组的索引就是角色(Qt.EditRole是2,Qt.ToolTipRole是3等等),所以我们只需要让某个角色来存放我们的数据,告诉比较操作符去比较这些值,并在设置数据时告诉setData设置DisplayRole,比如说我们的ValueRole。下面是一个示例:

class TreeItem(QtGui.QTreeWidgetItem):

    PythonValueRole = QtCore.Qt.UserRole

    #values are list of python objects, that have __str__ and can be compared
    def __init__(self, tree, values):
        QtGui.QTreeWidgetItem.__init__(self, tree)
        i = 0
        for v in values:
            self.setData(i, TreeItem.PythonValueRole, v)
            i += 1

    #overridden to simplify data assigning. When called with PythonValueRole, passes
    #that object's string representation to DisplayRole and EditRole
    def setData(self, col, role, value):
        if role == TreeItem.PythonValueRole:
            QtGui.QTreeWidgetItem.setData(self, col, TreeItem.PythonValueRole, value)
            # sets DisplayRole and EditRole
            QtGui.QTreeWidgetItem.setData(self, col, QtCore.Qt.EditRole, str(value)) 
            QtGui.QTreeWidgetItem.setData(self, col, QtCore.Qt.DisplayRole, str(value))
        else:
            QtGui.QTreeWidgetItem.setData(self, col, role, value)

    def __lt__(self, other):
        c = self.treeWidget().sortColumn()
        return self.data(c, TreeItem.PythonValueRole).toPyObject() < 
               other.data(c, TreeItem.PythonValueRole).toPyObject()

我测试过,这样做效果很好。当然,你也可以不使用继承,直接重载lt,因为我们有鸭子类型,可以直接使用UserRole来保存你的数据,并用setData(col, role, val)直接设置显示数据,或者只在编辑/显示角色中保存文本,在比较时再转换成日期时间,但这样看起来不太好。注意,data()包含QVariant。当你设置数据时,你的Python对象会自动转换,你需要调用toPyObject()才能把值恢复成原来的样子。

撰写回答