在PyQT4中使用QTreeWidgetItemIterator从QTreeWidget返回isChecked作为字典(或......某事)

时间:2013-12-16 19:06:56

标签: python pyqt pyqt4 qtreewidget qtreewidgetitem

检查最终代码的编辑!

所以...我会承认,由于缺乏知识,我在这里画了一个绝对的空白,只会出示我的代码并祈祷一点。

使用这个奇妙的xml到QTreeWidget生成器ekhumoro编码我已经在复选框中添加(三元组为父节点),现在我试图迭代这些复选框并返回一个字典或列表列表或...父母的东西:子(服务器:此树中的服务)关系,以便我可以从树的检查结果中构建文件夹的路径。这将在“开始”按钮上按下,作为系列中的第一个功能。

最终目标是使用一个工具根据用户提供的开始和停止时间从平台上的多个服务器和服务器中提取日志,并将这些日志传递到具有相同文件夹结构的管理框。 / p>

我已成功浏览测试字典,搜索并找到基于os.path.getctime和getmtime的文件,将其压缩,然后将它们复制到具有相同文件夹结构的单独驱动器,该驱动器是作为函数的一部分创建的。 ..

但是,我发现几乎没有关于TreeWidgetItemIterator(仅http://pyqt.sourceforge.net/Docs/PyQt4/qtreewidgetitemiterator.html#details)的文档,这对我没什么帮助。因此,这个拼图的整体(和最终)部分让我输了!

XMLHandler:

from PyQt4 import QtCore, QtGui, QtXml
from PyQt4.QtXml import *


class XmlHandler(QXmlDefaultHandler):
    def __init__(self, root):
        QtXml.QXmlDefaultHandler.__init__(self)
        self._root = root
        self._item = None
        self._text = ''
        self._error = ''

    def startElement(self, namespace, name, qname, attributes):
        if qname == 'Machine' or qname == 'Feature':
            if self._item is not None:
                self._item = QtGui.QTreeWidgetItem(self._item)
            else:
                self._item = QtGui.QTreeWidgetItem(self._root)
            self._item.setData(0, QtCore.Qt.UserRole, qname)
            self._item.setText(0, 'Unknown Machine')
            if qname == 'Machine':
                self._item.setExpanded(False)
                self._item.setCheckState(0, QtCore.Qt.Unchecked)
                self._item.setFlags(QtCore.Qt.ItemIsSelectable|QtCore.Qt.ItemIsDragEnabled|QtCore.Qt.ItemIsUserCheckable|QtCore.Qt.ItemIsEnabled|QtCore.Qt.ItemIsTristate)
            elif qname == 'FeatureName':
                self._item.setText(1, self._text)
        self._text = ''
        return True

    def endElement(self, namespace, name, qname):
        if qname == 'FeatureName' or qname == 'MachineName':
            if self._item is not None:
                self._item.setText(0, self._text)
                self._item.setCheckState(0, QtCore.Qt.Unchecked)
        elif qname == 'Feature' or qname == 'Machine':
            self._item = self._item.parent()
        return True

    def characters(self, text):
        self._text += text
        return True

    def fatalError(self, exception):
        print('Parse Error: line %d, column %d:\n  %s' % (
              exception.lineNumber(),
              exception.columnNumber(),
              exception.message(),
              ))
        return False

使用XmlHandler创建窗口小部件的类:

class MakeWidget(QtGui.QTreeWidget):
    def __init__(self):
        QtGui.QTreeWidget.__init__(self)
        self.header().setResizeMode(QtGui.QHeaderView.Stretch)
        self.setHeaderLabels(['Servers and Services'])
        source = QtXml.QXmlInputSource()
        source.setData(xml)
        handler = XmlHandler(self)
        reader = QtXml.QXmlSimpleReader()
        reader.setContentHandler(handler)
        reader.setErrorHandler(handler)
        reader.parse(source) 

在我的GUI中创建小部件:

        self.treeServiceSelection = MakeWidget(xml, parent=self.ui.groupBoxServiceSelection)

小部件与父母和子女有两个级别,这就是全部:

http://i.imgur.com/npPhG41.jpg

现在我们来到了被困的地方。我可以将信号绑定到按钮按下,我可以做其他所有事情但是从QTreeWidget获取dang检查项目。看来我需要构造一个迭代器并在其中使用Checked标志 init ,但我尝试过的任何东西都提出了bupkiss。我非常乐意为解决方案而努力,而不是为我提供一个解决方案,但没有一个起点令人沮丧。

编辑:所以我实际发布的内容都没有任何用处,但是ekhumoro理解了我的问题的关键并提供了他的解决方案(接受的答案)。我添加了一个elif来处理检查父项的任何内容(因为它似乎没有读到子项被检查为此效果):

def exportTree(self):
    mapping = defaultdict(list)
    root = self.tree.invisibleRootItem()
    for index in range(root.childCount()):
        parent = root.child(index)
        if parent.checkState(0) == QtCore.Qt.PartiallyChecked:
            features = mapping[parent.text(0)]
            for row in range(parent.childCount()):
                child = parent.child(row)
                if child.checkState(0) == QtCore.Qt.Checked:
                    features.append(child.text(0))
        elif parent.checkState(0) == QtCore.Qt.Checked:
            features = mapping[parent.text(0)]
            for row in range(parent.childCount()):
                features.append((parent.child(row)).text(0))
    return mapping

然后能够使用此示例根据gui中其他位置的另一个组合框选择特定的子项:

def checkbox2mods(self):
    d = {'DMD2K8COR2VM': ['CC2DCP', 'Centercord'],
         'DMD2K8COR1VM': ['CC2DCP', 'Centercord']}
    root = self.tree.invisibleRootItem()
    if self.checkBox2.checkState() == QtCore.Qt.Checked:
        for index in range(root.childCount()):
            parent = root.child(index)
            for row in range(parent.childCount()):
                child = parent.child(row)
                x = d.values()
                y = d.keys()
                for _ in x:
                    if child.text(0) in _:
                        if parent.text(0) in y:
                            child.setCheckState(0, QtCore.Qt.Checked)
                            parent.setExpanded(True)

我确定代码很讨厌,但只选择子代,它会部分检查父项,这样可以使导出功能正常工作。

2 个答案:

答案 0 :(得分:3)

我假设您的问题的核心是您想要遍历树窗口小部件并构建包含已检查项目的字典。

以下示例假定树的深度为两级,并且不会尝试对check-state进行任何管理:

# not needed for python 3
import sip
sip.setapi('QString', 2)

from collections import defaultdict
from PyQt4 import QtGui, QtCore

class Window(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.tree = QtGui.QTreeWidget(self)
        self.tree.header().hide()
        for index in range(5):
            parent = QtGui.QTreeWidgetItem(self.tree, ['NUS2K%s' % index])
            if index % 3:
                parent.setCheckState(0, QtCore.Qt.PartiallyChecked)
            else:
                parent.setCheckState(0, QtCore.Qt.Unchecked)
            features = 'Loader Reports Logging'.split()
            for count, item in enumerate(features):
                child = QtGui.QTreeWidgetItem(parent, [item])
                if index % 3 and count % 3:
                    child.setCheckState(0, QtCore.Qt.Checked)
                else:
                    child.setCheckState(0, QtCore.Qt.Unchecked)
            parent.setExpanded(True)
        self.button = QtGui.QPushButton('Export', self)
        self.button.clicked.connect(self.handleExport)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.tree)
        layout.addWidget(self.button)

    def handleExport(self):
        mapping = self.exportTree()
        for machine, features in mapping.items():
            print('%s:' % machine)
            for feature in features:
                print('  %s' % feature)

    def exportTree(self):
        mapping = defaultdict(list)
        root = self.tree.invisibleRootItem()
        for index in range(root.childCount()):
            parent = root.child(index)
            if parent.checkState(0) == QtCore.Qt.PartiallyChecked:
                features = mapping[parent.text(0)]
                for row in range(parent.childCount()):
                    child = parent.child(row)
                    if child.checkState(0) == QtCore.Qt.Checked:
                        features.append(child.text(0))
        return mapping

if __name__ == '__main__':

    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.setGeometry(800, 300, 300, 300)
    window.show()
    sys.exit(app.exec_())

答案 1 :(得分:1)

我使用下面的代码而不是遍历树

def updateTreeItems(self):
    for x in range(0,self.ConfigTree.topLevelItemCount()):
        topLvlItem = self.ConfigTree.topLevelItem(x)
        for y in range(numColums):
            self.updateHighlight(topLvlItem,y)
        if self.ConfigTree.isItemExpanded(topLvlItem):
            for i in range(0,topLvlItem.childCount()):
                childItem = topLvlItem.child(i)
                for y in range(numColums):
                    self.updateHighlight(childItem,y)

我使用self.updateHighlight(childItem,y)来突出显示树中的单元格,但您可以将某些数据添加到列表或其他内容 - 如果已选中。

我在阅读你的问题时遇到了一些麻烦,但是如果我离开的话请告诉我? - 我想我可以提供帮助,因为我现在已经使用了一些树:-)