【问题标题】:PyQt Tree Widget, adding check boxes for dynamic removalPyQt Tree Widget,为动态移除添加复选框
【发布时间】:2015-09-29 06:56:11
【问题描述】:

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

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

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

任何建议如何实施?我不知道它是否对难度有影响,但我已经为复选框分配了一个单独的列。

【问题讨论】:

    标签: python checkbox pyqt qtreeview qtreewidgetitem


    【解决方案1】:

    除了您提供的answer,您还可以通过在父元素上使用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)
    

    这些将孩子设置为可选并将默认设置为未选中。如果孩子的复选框没有被赋予状态,复选框元素不会出现。


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

    但是,如果我选中父元素上的复选框,则会自动选中所有子元素:

    如果,我想取消选择一个孩子,父母进入部分选择(三态):

    如果取消选择所有子项,则自动取消选择父项。如果父级未选中,所有子级也将自动取消选中。

    【讨论】:

    • 这似乎工作得很好,但是我的框并没有得到一个很好的填充框,而是看起来只是有一个水平破折号穿过它们,或者如果我再次单击它,它会显示一个复选标记。这是正常的吗?无论如何我可以禁用实心破折号或修复它以填充整个框,如您的示例所示?
    • 这取决于您的操作系统和小部件样式。有更多关于 here 的文档,但可能超出了这个特定问题的范围。
    • 好的,有没有办法禁用整个填充并使其只有检查选项?
    • 如果您只希望它是一个二进制复选框而不是一个三态框,请删除Qt.ItemIsTristate 标志并添加parent.setCheckState(0, Qt.Unchecked)(同样,它需要一个复选框状态才能显示)。这会将复选框添加到父级。但是,通过删除三态标志,您将失去对子项的自动选择和取消选择。
    • 是否有任何简单的方法可以返回当前选中的所有框的列表?除了编写一个循环遍历整个树检查每个项目的检查状态之外?
    【解决方案2】:

    我将 @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()
    

    【讨论】:

      【解决方案3】:

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

      例如:

      item = QTreeWidgetItem(self.treeWidget)
      
      item.setCheckState(0, QtCore.Qt.Unchecked)
      

      【讨论】:

      • 是的,但您的解决方案不包括父级具有与其子级状态相对应的三态的层次结构。上面列出的示例确实如此。
      【解决方案4】:

      这不是您问题的答案,而是您拥有复选框后如何使用它们。我从标记为正确的答案中使用了上面的示例。它起作用了,但是当我试图找到如何知道标记了哪些复选框时,我遇到了很多问题。经过大量搜索,我找到了一个适合我的解决方案,因为我看到没有很多文档,所以我想为将来留下记录。顺便提一下,我使用了几个解决方案作为 invisibleRootItem 来找到父级的子级,但这没有用。

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

      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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-01
        • 2021-03-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多