PySide Qt 在叶项处插入行并更新视图

Posted

技术标签:

【中文标题】PySide Qt 在叶项处插入行并更新视图【英文标题】:PySide Qt insert row at leaf item and update view 【发布时间】:2015-03-26 06:18:05 【问题描述】:

我有这个大部分工作的代码,使用户能够将项目添加到树结构中。只要您不向叶项(没有子项的项)添加项,这就可以正常工作。

如果项目没有子项目,那么在第一次添加子项目时,视图根本不会更新。您可以通过卷起父项并重新展开它来更新视图。或者,添加第二个子项会导致视图更新(您可以看到两个项都添加了)。

如何在将第一个子项添加到叶项后更新视图?

更新:您也可以双击新的父级,它的子级将显示,但没有扩展小部件。似乎没有发生的是,在满足上述条件之一之前,小扩展项小部件不会显示。

from PySide import QtCore, QtGui
import sys


model_data = [
    [1, [2, [3, 4]]],
    [5, [6, 7]],
    [8, [9]],
    [10]
]


class MyData:

    def __init__(self, number, parent=None):
        ''''''
        self.number = number
        self.children = []
        self.parent = parent
        if parent is not None:
            parent.addChild(self)


    def row(self):
        ''''''
        row = None
        if self.parent is None:
            row = 0
        else:
            for i, item in enumerate(self.parent.children):
                if item == self:
                    row = i
                    break

        return row


    def addChild(self, item):
        ''''''
        self.children.append(item)
        item.parent = self


class TreeModel(QtCore.QAbstractItemModel):

    def __init__(self, top, *args, **kwargs):
        ''''''
        super(TreeModel, self).__init__(*args, **kwargs)
        self.__top = top


    def index(self, row, column, parent=QtCore.QModelIndex()):
        ''''''
        if parent.isValid():
            parent_node = parent.internalPointer()
            node = parent_node.children[row]
            index = self.createIndex(row, column, node)
        else:
            index = self.createIndex(row, column, self.__top)
        return index


    def parent(self, index):
        ''''''
        if index.isValid():
            node = index.internalPointer()
            parent = node.parent
            if parent is None:
                parent_index = QtCore.QModelIndex()
            else:
                parent_index = self.createIndex(parent.row(), 0, parent)
        else:
            parent_index = QtCore.QModelIndex()
        return parent_index


    def rowCount(self, index=QtCore.QModelIndex()):
        ''''''
        node = index.internalPointer()
        if node is None:
            count = 1
        else:
            count = len(node.children)
        return count


    def columnCount(self, index=QtCore.QModelIndex()):
        ''''''
        return 1


    def data(self, index, role=QtCore.Qt.DisplayRole):
        ''''''
        if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
            node = index.internalPointer()
            data = str(node.number)

        else:
            data = None

        return data


    def addChild(self, index, child):
        self.beginInsertRows(index, self.rowCount(index), self.rowCount(index)+1)

        parent = index.internalPointer()
        parent.addChild(child)

        self.endInsertRows()


class Window(QtGui.QMainWindow):

    def __init__(self):
        super(Window, self).__init__()

        self.build_model()

        self.add_item_action = QtGui.QAction('New &Item', self)
        self.add_item_action.triggered.connect(self.add_item)

        self.view = QtGui.QTreeView()
        self.view.setModel(self.model)

        self.setCentralWidget(self.view)
        self.show()


    def build_model(self):
        def recurse(parent, children_data):
            for child_data in children_data:
                if isinstance(child_data, list):
                    recurse(child, child_data)
                else:
                    child = MyData(child_data, parent=parent)

        top = MyData(0)                      
        for i, next in enumerate(model_data):
            recurse(top, next) 
        self.model = TreeModel(top)


    def add_item(self):
        ''''''
        index = self.view.currentIndex()
        new_item = MyData(0)
        self.model.addChild(index, new_item)


    def contextMenuEvent(self, event):
        ''''''
        contextMenu = QtGui.QMenu()
        contextMenu.addAction(self.add_item_action)
        contextMenu.exec_(event.globalPos())


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    window = Window()
    sys.exit(app.exec_())

【问题讨论】:

也许你可以使用void QAbstractItemView::update (const QModelIndex &index)(是的,它的c++,但是python绑定应该有类似的方法 【参考方案1】:

除非模型知道布局发生了更改,否则它不会始终正确更新。所以试试这个:

    def addChild(self, index, child):
        ...
        self.endInsertRows()
        self.layoutChanged.emit()

【讨论】:

谢谢,解决我的问题,我已经调用了 beginInsertRows 和 endInsertRows,没有帮助,添加 self.layoutChanged.emit() 后,它可以工作了。

以上是关于PySide Qt 在叶项处插入行并更新视图的主要内容,如果未能解决你的问题,请参考以下文章

使用 Pyside 的 Qt 树视图

更新集合视图项

如何以编程方式从 SwiftUI 列表中删除行并刷新列表视图?

数据库视图性能问题

更新数据表中的切割行并添加新记录 ASP.NET MVC

一个模型,两个不同的视图 - PySide