lazy loading child items Qtreeview

≡放荡痞女 提交于 2019-12-24 00:36:28

问题


I am trying to load child items in a treeview

+top
  parent1
  parent2
  parent3

To start off I populate the model with parent node information only and attach it to a treeview, the tree looks like above.

self.mytreeview=QtGui.Qtreeview()
self.model=QtGui.QStandardItemModel(self.mytreeview)

def initialise_model(self):
    '''Populate the model with parent nodes only'''
    #open file and process each line, each file line has the parent node info
    ....

    for file_name_entry in fileobject:
        parent_item=QtGui.QStandardItem(str(file_name_entry).strip())
        parent_item.setData("this is a parent",QtCore.Qt.TooltipRole)
        self.model.appendRow(parent_item)
    self.mytreeview.setModel(self.model)

At this point none of the parents have any child information. What I want to do next is to update a parent node, when the user clicks on the parent node(just in time or lazy loading of a parents child information).

So when a parent node is clicked, and the signal is emitted

QtCore.QObject.connect(self.ui.treeView, QtCore.SIGNAL('clicked(QModelIndex)'), self.update_model)

update_model code should go fetch the children of that parent, update the model, refresh the tree and expand the parent node.

    def update_model(self,index):
        '''Update the model by adding children to selected/clicked parent node only'''
        parent_node=QtGui.QStandardItem(self.model.itemFromIndex(index))
        parent_item_index=index.row()
        #open the file called parent_node.txt and get all the child entries from the file...
        child_index=0
        for child_name_entry in parent_text_fileobject:
            child_item=QtGui.QStandardItem(str(child_name_entry).strip())
            child_item.setData("this is a child",QtCore.Qt.TooltipRole)
            parent_item.setChild(child_index,child_item)
            child_index=child_index+1
#Once all the children have been added update the model, by inserting a new row where the parent was
        self.model.removeRow(parent_item_index)#remove old parent
        self.model.insertRow(parent_item_index,parent_item)#insert new parent with its children

When I try to remove the selected parent node (the one with no children) and try inserting a new parent item (with children) it ends up addding the new parent(with children) above the parent node with no children so I end up with duplicated parent nodes

+top
  parent1
  parent2
  +parent2
    child_a
    child_b
    child_c  
  parent3

So just to recap, removing and inserting i.e.

#Once all the children have been added update the model, by inserting a new row where the parent was
        self.model.removeRow(parent_item_index)#remove old parent
        self.model.insertRow(parent_item_index,parent_item)#insert new parent with its children

is a bad idea. Looking at the comments its been suggested that AppendRow() might be the answer, but I am not so certain I believe that

self.model.appendRow(parent_item)#new parent with its children

Would simply add the parent to the bottom of my model and therefore the tree would still have duplicate parent nodes i.e

+top
  parent1
  **parent2**
  parent3
  **+parent2**
    child_a
    child_b
    child_c  

I think what I am looking for is a way to update an existing node in the model, so that the selected (parent node) can be updated with its children. e.g.

...
    self.model.UpdateExisitingNode(node_index)
...

Any suggestions on how to update an node in model? Note I am using Windows and PyQt

Regards


回答1:


You are duplicating items because you are creating another parent item, you should only create new child items. For example:

from PyQt4 import QtGui


class Widget(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.mytreeview = QtGui.QTreeView(self)
        self.setLayout(QtGui.QVBoxLayout())
        self.layout().addWidget(self.mytreeview)
        self.model = QtGui.QStandardItemModel(self.mytreeview)
        self.mytreeview.setModel(self.model)
        self.mytreeview.clicked.connect(self.update_model)
        self.initialise_model()

    def initialise_model(self):
        for text in ["parent1", "parent2", "parent3"]:
            item = QtGui.QStandardItem(text)
            self.model.appendRow(item)

    def update_model(self, index):
        parent = self.model.itemFromIndex(index)
        for text in ["children1", "children2", "children3"]:
            children = QtGui.QStandardItem("{}_{}".format(parent.text(), text))
            parent.appendRow(children)
        self.mytreeview.expand(index)


if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())



回答2:


To get this to work nicely, the parent items should show expansion arrows before they are populated with child items. It would also be nice to populate the top-level items when expaned by whatever means (i.e. via the mouse, the keyboard, and also programmatically), whilst at the same time ensuring that this only happens when required (i.e. only if the parent is currently empty).

This can all be achieved quite simply by setting an "Expandable" flag on the relevant items and then reimplementing the hasChildren method of the QStandardItemModel. With that in place, it is then very easy to write methods to populate the top-level items on demand.

Here is a simple demo based on your example code that implements all that:

import sys
from PyQt4 import QtCore, QtGui

class StandardItemModel(QtGui.QStandardItemModel):
    ExpandableRole = QtCore.Qt.UserRole + 500

    def hasChildren(self, index):
        if self.data(index, StandardItemModel.ExpandableRole):
            return True
        return super(StandardItemModel, self).hasChildren(index)

class Window(QtGui.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.mytreeview = QtGui.QTreeView()
        self.model = StandardItemModel(self.mytreeview)
        self.mytreeview.setModel(self.model)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.mytreeview)
        self.mytreeview.expanded.connect(self.update_model)
        self.initialise_model()

    def initialise_model(self):
        self.model.clear()
        for file_name_entry in fileobject:
            parent_item = QtGui.QStandardItem(file_name_entry.strip())
            parent_item.setData(True, StandardItemModel.ExpandableRole)
            parent_item.setData("this is a parent", QtCore.Qt.ToolTipRole)
            self.model.appendRow(parent_item)

    def update_model(self, index):
        parent_item = self.model.itemFromIndex(index)
        if not parent_item.rowCount():
            for child_name_entry in parent_text_fileobject:
                child_item = QtGui.QStandardItem(child_name_entry.strip())
                child_item.setData("this is a child", QtCore.Qt.ToolTipRole)
                parent_item.appendRow(child_item)

# dummy test data
fileobject = 'parent1 parent2 parent3'.split()
parent_text_fileobject = 'child_a child_b child_c'.split()

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())


来源:https://stackoverflow.com/questions/46778623/lazy-loading-child-items-qtreeview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!