如何创建一个代理模型,将 QAbstractItemModel 的节点展平为 PySide 中的列表? [英] How to create a proxy model that would flatten nodes of a QAbstractItemModel into a list in PySide?

查看:42
本文介绍了如何创建一个代理模型,将 QAbstractItemModel 的节点展平为 PySide 中的列表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个由自定义 QAbstractItemModel 表示的节点层次结构.是否可以创建一个代理模型,将层次结构展平为一个列表,以允许我在 QListView 中显示所有节点/项目(没有代理,只显示树的第一级)?

I have a hierarchy of nodes represented by a custom QAbstractItemModel. Is it possible to create a proxy model that would flatten the hierarchy into a list to allow me to present all the nodes/items in a QListView (without a proxy only the first level of the tree gets presented)?

A                           A
+---1                       1
    2                       2
    +--3                    3
    4            =>         4
B                           B
+---5                       5
    6                       6
    +--7                    7
       8                    8

谢谢,菲普斯

推荐答案

QTreeView 强制转换为列表视图更容易:

It's way easier to just coerce a QTreeView to look like a list view:

view = QtGui.QTreeView()
view.setModel(model)
view.expandAll()
view.setIndentation(0)
view.header().hide() 

如果您真的想这样做,代理不是最简单的事情,因为它需要保留源模型的结构模型.对于改变其结构的源模型,代理还必须跟踪源模型的结构.

If you really wish to do it, the proxy isn't the most trivial affair, since it needs to retain a structural model of the source model. For a source model that changes its structure, the proxy must also keep track of the structure of the source model.

作为起点,以下是具有静态结构的模型的最小实现.我只在 Python 3.3 上测试过.更改在视图之间传播 - 您可以在任一视图中编辑项目的文本,底层树模型将被修改,并相应地通知另一个视图.

As a starting point, below is a minimal implementation for a model with static structure. I've only tested it on Python 3.3. The changes are propagated between the views - you can edit the text of an item in either view, and the underlying tree model will be modified, and the other view appropriately notified.

代理应该简单地传递列表模型,因为它们已经是扁平的.为了演示这种透明度,右窗格是附加到中间窗格中查看的代理的代理的列表视图.在中间窗格中查看的代理附加到在左侧窗格中查看的树模型.

The proxy should simply pass-through list models, as they are already flat. To demonstrate this transparency, the right pane is a list view of a proxy attached to the proxy viewed in the middle pane. The proxy viewed in the middle pane is attached to the tree model viewed in the left pane.

很高兴接受那些真正了解 Python/PySide 的人的编辑.目前我对 Python 的了解非常休闲.

I gladly accept edits by those who actually know Python/PySide. My knowledge of Python is very recreational at the moment.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
from PySide import QtCore, QtGui

class FlatProxyModel(QtGui.QAbstractProxyModel):
    @QtCore.Slot(QtCore.QModelIndex, QtCore.QModelIndex)
    def sourceDataChanged(self, topLeft, bottomRight):
        self.dataChanged.emit(self.mapFromSource(topLeft), \
                              self.mapFromSource(bottomRight))
    def buildMap(self, model, parent = QtCore.QModelIndex(), row = 0):
        if row == 0:
            self.m_rowMap = {}
            self.m_indexMap = {}
        rows = model.rowCount(parent)
        for r in range(rows):
            index = model.index(r, 0, parent)
            print('row', row, 'item', model.data(index))
            self.m_rowMap[index] = row
            self.m_indexMap[row] = index
            row = row + 1
            if model.hasChildren(index):
                row = self.buildMap(model, index, row)
        return row
    def setSourceModel(self, model):
        QtGui.QAbstractProxyModel.setSourceModel(self, model)
        self.buildMap(model)
        print(flush = True)
        model.dataChanged.connect(self.sourceDataChanged)
    def mapFromSource(self, index):
        if index not in self.m_rowMap: return QtCore.QModelIndex()
        #print('mapping to row', self.m_rowMap[index], flush = True)
        return self.createIndex(self.m_rowMap[index], index.column())
    def mapToSource(self, index):
        if not index.isValid() or index.row() not in self.m_indexMap:
            return QtCore.QModelIndex()
        #print('mapping from row', index.row(), flush = True)
        return self.m_indexMap[index.row()]
    def columnCount(self, parent):
        return QtGui.QAbstractProxyModel.sourceModel(self)\
               .columnCount(self.mapToSource(parent))
    def rowCount(self, parent):
        #print('rows:', len(self.m_rowMap), flush=True)
        return len(self.m_rowMap) if not parent.isValid() else 0
    def index(self, row, column, parent):
        #print('index for:', row, column, flush=True)
        if parent.isValid(): return QtCore.QModelIndex()
        return self.createIndex(row, column)
    def parent(self, index):
        return QtCore.QModelIndex()
    def __init__(self, parent = None):
        super(FlatProxyModel, self).__init__(parent)

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)

    model = QtGui.QStandardItemModel()
    names = ['Foo', 'Bar', 'Baz']
    for first in names:
        row = QtGui.QStandardItem(first)
        for second in names:
            row.appendRow(QtGui.QStandardItem(first+second))
        model.appendRow(row)

    proxy = FlatProxyModel()
    proxy.setSourceModel(model)

    nestedProxy = FlatProxyModel()
    nestedProxy.setSourceModel(proxy)

    w = QtGui.QWidget()
    layout = QtGui.QHBoxLayout(w)
    view = QtGui.QTreeView()
    view.setModel(model)
    view.expandAll()
    view.header().hide()
    layout.addWidget(view)
    view = QtGui.QListView()
    view.setModel(proxy)
    layout.addWidget(view)
    view = QtGui.QListView()
    view.setModel(nestedProxy)
    layout.addWidget(view)
    w.show()

    sys.exit(app.exec_())

这篇关于如何创建一个代理模型,将 QAbstractItemModel 的节点展平为 PySide 中的列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆