Check the edit for final code!
So...I'll admit that I'm drawing an absolute blank here due to lack of knowledget and will just present my code and pray a little bit.
Using this fantastic xml to QTreeWidget generator that ekhumoro coded I've added in checkboxes (tristate for parent nodes) and now I'm attempting to iterate over these checkboxes and return a dictionary or a list of lists or...something with a parent:children (server:services in this tree) relationship so that I can build paths to folders out of the tree's checked results. This would occur on a 'Start' button press as the first function in a series.
The end goal is to have a tool that pulls logs from multiple servers and services-per-server on a platform based on a user provided start and stop time, and deliver these logs to an admin box with identical folder structure.
I've successfully navigated through a test dictionary, searched for and located files based on os.path.getctime and getmtime, zipped them, then copied them to a seperate drive with identical folder structure that's created as part of a function...
However, I've found literally almost no documentation on the TreeWidgetItemIterator (only http://pyqt.sourceforge.net/Docs/PyQt4/qtreewidgetitemiterator.html#details) which wasn't very helpful to me. So the integral (and final) piece to this puzzle has me lost!
The 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
The Class that uses XmlHandler to make the widget:
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)
Creation of the widget in my GUI:
self.treeServiceSelection = MakeWidget(xml, parent=self.ui.groupBoxServiceSelection)
The widget is two level with parents and children, and that's all:
https://i.stack.imgur.com/mqoO5.jpg
And now we've come to where I'm stuck. I can tie the signal to the button press, I can do everything else but get the dang checked items from the QTreeWidget. It seems that I would need to construct an iterator and have the Checked flag in it's init but anything that I've tried has come up with bupkiss. I'm more than happy to work to a solution rather than have one provided to me, but not having a starting point has been depressing.
Edit: So none of what I actually posted was of any use, but ekhumoro understood the crux of my question and provided his solution (the accepted answer). I added one an elif
to handle anything where a parent was checked (as it didn't seem to read that the children were checked as an effect of this):
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
and then was able to use this example to select specific children based on another comboBox elsewhere in the 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)
I'm sure the code is nasty, but by only selecting the children it partial checks the parents, which allows for the export function to work correctly.
Im assuming that the core of your question is that you want to iterate over a tree widget and build a dictionary containing the checked items.
The example below assumes the tree is two levels deep, and doesn't attempt any management of check-state: