Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QTreeWidget select first item

I am making a QTreeWidget from a XML file. The XML looks like below and I want to make a tree of the names:

<root>
    <f name='foo'>bar
        <f name='foo2'>baz</f>
    </f>
</root>

At the moment I am using the following code to do so (somewhat simplified code):

import lxml.etree as et

#...

self.xml = et.XML(filters.filtersxml)
self.tree_widget = QTreeWidget(parent)

def add_items(parent, xmlroot):
    for i in xmlroot.getchildren():
        item = QTreeWidgetItem(parent, [i.get('name')])
        if len(i.getchildren()) != 0:
            add_items(item, i)

add_items(self.tree_widget, self.xml)

I actually have two questions about this:

  1. Main question: Is there some way to select the first item in the tree, foo in this case. I tried to do something with setCurrentItem() and setCurrentIndex(), but couldn't get it to work. I have googled a bit about it, but all the solutions that I found work with models.
  2. (Optional) Is this recursive function a good approach to do this, or is there a better way?
like image 720
BrtH Avatar asked Aug 16 '12 23:08

BrtH


1 Answers

Recursive is good, would keep it that way, and in answer to your main question just do:

# after all your code
add_items(self.tree_widget, self.xml)

# select the root item
self.tree_widget.setCurrentItem(self.tree_widget.topLevelItem(0))

You just have to make sure that the item has already been added to the tree when you call setCurrentItem - otherwise it won't really work. Some methods require the item to already be associated to a tree (like setExpanded and setSelected)

Edit

To build up recursively without affecting the tree, you can do:

import lxml.etree as et

#...

self.xml = et.XML(filters.filtersxml)
self.tree_widget = QTreeWidget(parent)

def add_items(parent, xmlroot):
    output = []
    for i in xmlroot.getchildren():
        item = QTreeWidgetItem(parent, [i.get('name')])
        output.append(item)
        if len(i.getchildren()) != 0:
            add_items(item, i)
    return output

items = add_items(None, self.xml)
self.tree_widget.addTopLevelItems(items)
self.tree_widget.setCurrentItem(items[0])

Edit 2: Loading all at once

And to go a bit further down the rabbit hole, the way that I would personally do this to minimize unnecessary calls and lists as much as possible would be to build the loop the children only once:

import lxml.etree as et

#...

self.xml = et.XML(filters.filtersxml)
self.tree_widget = QTreeWidget(parent)

def create_item(parent, xmlroot):
    item = QTreeWidgetItem(parent, [xmlroot.get('name')])
    for xmlchild in xmlroot.getchildren():
       create_item(item, xmlchild)
    return item

items = [create_item(None, xmlchild) for xmlchild in self.xml.getchildren()]
self.tree_widget.addTopLevelItems(items)
if ( items ):
    self.tree_widget.setCurrentItem(items[0])

Edit 3: Loading dynamically

And since it was brought up...a way to dynamically load the children would be to store each level and load them after being expanded:

import lxml.etree as et
from PyQt4.QtGui import QTreeWidgetItem

# ...    

class XmlTreeWidgetItem(QTreeWidgetItem):
    def __init__( self, parent, xmlitem ):
        super(MyTreeWidgetItem, self).__init__(parent)
        self.setText(0, xmlitem.get('name'))
        self.setChildIndicatorPolicy(self.ShowIndicator)

        self._xmlitem = xmlitem
        self._loaded = False

    def loadChildren( self ):
        if ( self._loaded ):
            return

        self._loaded = True
        self.setChildIndicatorPolicy(self.DontShowIndicatorWhenChildless)
        for xmlchild in self._xmlitem.getchildren():
            XmlTreeWidgetItem(self, xmlchild)

# ...

class SomeClass(QWidget):
    def __init__( self, parent = None ):
        super(SomeClass, self).__init__(parent)

        self.tree_widget = QTreeWidget(parent)

        xml = et.XML(filters.filtersxml)
        items = [XmlTreeWidgetItem(None, xchild) for xchild in xml.getchildren()]
        self.tree_widget.addTopLevelItems(items)
        if ( items ):
            self.tree_widget.setCurrentItem(items[0])

        # create connections
        self.tree_widget.itemExpanded.connect(self.loadItem)

    def loadItem( self, item ):
        item.loadChildren()
like image 159
Eric Hulser Avatar answered Nov 15 '22 13:11

Eric Hulser