跨越多个列,使用QTreeView和QAbstractItemModel



我想制作一个TreeView,其中顶层条目跨越所有列(例如它们有一行),而子条目跨越多个列(例如它们有多行)

我试图完成这与qtreeview . setfirstcolumnspan。然而,我真的不知道在哪里/什么时候调用它(也许我一开始就完全错了)

我想也许我可以在我的视图中创建一个函数,该函数将在视图填充后调用,以检查需要更新其跨度的任何项目。

然而,我找不到任何可以连接的信号来帮助我这样做(我尝试了几个,但似乎没有一个触发)

我还尝试重新实现insertRows在我的模型和/或rowsInserted在我的视图,但他们似乎从来没有被调用。

这是我正在做的一个极其简化的版本:

class MyModel(QtCore.QAbstractItemModel):
    def __init__(self, top_level_nodes):
        QtCore.QAbstractItemModel.__init__(self)
        self.top_level_nodes = top_level_nodes
        self.columns = 5
    def columnCount(self, parent):
        return self.columns
    def rowCount(self, parent):
        total = len(self.top_level_nodes)
        for node in self.top_level_nodes:
            total += len(node.subnodes)
        return total
    def data(self, index, role):
        if not index.isValid():
            return QtCore.QVariant()
        if role == QtCore.Qt.DisplayRole:
            obj = index.internalPointer()
            return obj.name
        return QtCore.QVariant()
    def index(self, row, column, parent):
        if not parent.isValid():
            if row > (len(self.top_level_nodes) - 1):
                return QtCore.QModelIndex()
            return self.createIndex(row, column, self.top_level_nodes[row])
        return QtCore.QModelIndex()
    def parent(self, index):
        if not index.isValid():
            return QtCore.QModelIndex()
        node = index.internalPointer()
        if node.parent is None:
            return QtCore.QModelIndex()
        else:
            return self.createIndex(node.parent.row, 0, node.parent)
class FakeEntry(object):
    def __init__(self, name, row, children=[]):
        self.parent = None
        self.row = row
        self.name = 'foo'
        self.subnodes = children
class MainWindow(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.resize(800, 600)
        self.layout = QtGui.QVBoxLayout(self)
        self.tree_view = QtGui.QTreeView(self)
        self.layout.addWidget(self.tree_view)
        entry = FakeEntry('foo', 0, children=[])
        self.model = MyModel([entry])
        self.tree_view.setModel(self.model)
def main():
    app = QtGui.QApplication(sys.argv)
    frame = MainWindow()
    frame.show()
    sys.exit(app.exec_())
if __name__ == '__main__':
    main()

这段代码运行良好。我需要知道的是:

我如何使由FakeEntry创建的条目跨越所有5列而不是创建5个相同的单元格?

其他问题:

  • 我可以重新实现QAbstractItemModel。insertRows或QTreeView.rowsInserted?是否有我遗漏的"技巧"来做到这一点,从而导致我的代码选择默认实现?
  • 什么实际处理创建视图中的行/列,一旦模型与数据填充并附加到视图?

如果我在MainWindow.__init__()中的setModel()呼叫后添加对setFirstColumnSpanned的呼叫,这对我来说是有效的。

class MainWindow(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.resize(800, 600)
        self.layout = QtGui.QVBoxLayout(self)
        self.tree_view = QtGui.QTreeView(self)
        self.layout.addWidget(self.tree_view)
        entry = FakeEntry('foo', 0, children=[])
        self.model = MyModel([entry])
        self.tree_view.setModel(self.model)
        self.tree_view.setFirstColumnSpanned(0, QtCore.QModelIndex(), True)

我相信视图在内部跟踪跨列,与模型分开。但是无论何时调用setModel(),它都会重置跨度信息。因此,您应该在视图上调用setModel()之后调用setFirstColumnSpanned()。如果你的模型正在使用fetchMore()进行延迟加载,你必须找出一些方法来通知视图,它应该在模型加载新数据后更新跨度。

关于在视图中创建行/列的实际处理,我认为这是模型和视图之间的伙伴关系。一旦视图有了模型集,它就开始向模型提出各种问题。对于最上面的父项(无效索引),有多少列?很好,有5个。有多少行?好的,1。根据这些信息,视图的头部可以开始配置自己。在某一点上,视图遍历模型中的行、列和子节点,并依次为每个数据角色向每个索引请求其数据。然后,它可以开始创建委托,以便在视图的适当位置显示该数据。

相关内容

  • 没有找到相关文章

最新更新