PyQt树形控件,为动态删除添加复选框

7

我正在尝试创建一种树形小部件,它实质上允许用户查看各种数据细分,并具有删除某些项的选项。为了做到这一点,我希望每个顶级项目和每个子级都与复选框相关联,以便用户可以选择要删除哪些顶级项目(因此删除该顶级项目的所有子项)或要删除哪些特定子项。为了给您更好的理解,我创建了一个示例,其中[x]表示已选中的复选框,[ ]表示未选中的复选框:

>Beverages Allowed in Stadium [ ]
    Soda                      [ ]
    Water                     [ ]
    Tea                       [ ]
    Spirits                   [X]
    Ale                       [ ]

>Tickets                      [X]
    Row A                     [X]
    Row B                     [X]
    Row C                     [X]
    Lawn                      [X]

有什么建议可以实现这个吗?我不知道是否会影响难度,但我已经为复选框分配了一个单独的列。
4个回答

23

除了您提供的答案外,您还可以通过在父元素上使用ItemIsTristate标志来简化您的逻辑。

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

def main(): 
    app     = QApplication (sys.argv)
    tree    = QTreeWidget ()
    headerItem  = QTreeWidgetItem()
    item    = QTreeWidgetItem()

    for i in xrange(3):
        parent = QTreeWidgetItem(tree)
        parent.setText(0, "Parent {}".format(i))
        parent.setFlags(parent.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
        for x in xrange(5):
            child = QTreeWidgetItem(parent)
            child.setFlags(child.flags() | Qt.ItemIsUserCheckable)
            child.setText(0, "Child {}".format(x))
            child.setCheckState(0, Qt.Unchecked)
    tree.show() 
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

最重要的三行代码是:

parent.setFlags(parent.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)

这个将父元素设置为三状态复选框。

child.setFlags(child.flags() | Qt.ItemIsUserCheckable)
child.setCheckState(0, Qt.Unchecked)

这些设置使得子元素可以被选择并将默认设置为未选中状态。如果子复选框没有给定状态,则复选框元素不会出现。


上面的代码构建了一个非常简单的树形结构。

Simple Tree

然而,如果我在父元素上勾选一个复选框,则所有子元素会自动被选中:

Parent Selected

如果我想取消选择一个单个子元素,则父元素进入部分选中状态(三态):

TriState

如果所有子元素都未选中,则父元素会自动变为未选中状态。如果父元素未选中,则所有子元素也会自动变为未选中状态。


您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - sudobangbang
1
这取决于您的操作系统和小部件样式。关于这个问题,这里有更多的文档,但可能超出了这个具体问题的范围。 - Andy
好的,有没有办法只禁用整个填充并使其仅具有复选框选项? - sudobangbang
1
如果你只想让它成为一个二进制复选框而不是三态框,那么请移除 Qt.ItemIsTristate 标志并添加 parent.setCheckState(0, Qt.Unchecked)(再次强调,需要复选框状态才能显示)。这将把复选框添加到父级。但是,通过移除 Tristate 标志,你会失去自动选择和取消子项的功能。 - Andy
有没有一种简单的方法可以返回所有当前选中的框的列表?除了编写一个循环来遍历整个树并检查每个项目的状态之外? - sudobangbang
@sudobangbang 我正在使用以下代码来检索已选中的子项(和父项): root = treeWidget.invisibleRootItem() for i in range(root.childCount()): item = root.child(i) if item.checkState(0, QtCore.Qt.Checked): # 进行某些操作或添加到列表中 (PS:我不知道如何格式化它使其看起来漂亮) - Itamar Bitton

8
我将@andy的精彩示例移植到了PyQt5:
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5.Qt import Qt
import sys

def main(): 
    app     = QtWidgets.QApplication(sys.argv)
    tree    = QtWidgets.QTreeWidget()
    headerItem  = QtWidgets.QTreeWidgetItem()
    item    = QtWidgets.QTreeWidgetItem()

    for i in range(3):
        parent = QtWidgets.QTreeWidgetItem(tree)
        parent.setText(0, "Parent {}".format(i))
        parent.setFlags(parent.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
        for x in range(5):
            child = QtWidgets.QTreeWidgetItem(parent)
            child.setFlags(child.flags() | Qt.ItemIsUserCheckable)
            child.setText(0, "Child {}".format(x))
            child.setCheckState(0, Qt.Unchecked)
    tree.show() 
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

screenshot


4

QTreeWidgetItem 实际上有一个内置复选框,您可以相当容易地使用它。

例如:

item = QTreeWidgetItem(self.treeWidget)

item.setCheckState(0, QtCore.Qt.Unchecked)

是的,但您的解决方案不包括层次结构,其中父级具有与其子级状态相对应的三态。上面列出的示例包括此功能。 - MaVCArt

2

这不是对你的问题的答案,而是关于如何在拥有复选框后使用它们。我使用了上面标记为正确答案的示例。它起作用了,但当我尝试找出哪些复选框被标记时,我遇到了很多问题。经过大量搜索,我找到了一个适合我的解决方案,因为我看到没有太多文档,所以我想留下记录供将来参考。只是提一下,我使用了几个解决方案,例如invisibleRootItem来查找父项的子项,但那并没有起作用。

最终,我使用了类QTreeWidgetItemIterator,并使用标志QtGui.QTreeWidgetItemIterator.Checked来检索标记的复选框的文本,有了这个,我可以继续工作。

def vrfs_selected(self):
    iterator = QtGui.QTreeWidgetItemIterator(self.tree, QtGui.QTreeWidgetItemIterator.Checked)
    while iterator.value():
        item = iterator.value()
        print (item.text(0))    
        iterator += 1

文档链接 http://ftp.ics.uci.edu/pub/centos0/ics-custom-build/BUILD/PyQt-x11-gpl-4.7.2/doc/html/qtreewidgetitemiterator.html 和示例链接 https://riverbankcomputing.com/pipermail/pyqt/2014-May/034315.html


这是答案的第二部分。 - user3711502

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接