LoginSignup
3
3

More than 5 years have passed since last update.

PySideでモデルイテレータを作る

Last updated at Posted at 2016-12-23

PySideでツリー型のモデルを作成した際に、すべてのアイテムを順次アクセスしたい場合がある。

QTreeWidgetを使用ている場合は、QTreeWidgetItemIteratorで順次アクセスする事ができる。(C++用のライブラリなのでpythonだと若干使い勝手が悪いが)
QStandardItemModelや独自のモデルでもイテレータを使いたいので作成した。

コードはpython2だが、xrangeを使っていないのでpython3でもそのまま動く。

コード

#! usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals, print_function, absolute_import
from PySide.QtCore import *
from PySide.QtGui import *


def model_iter(model, parent_index=QModelIndex(), col_iter=True):
    """ モデルのイテレータ
    :rtype: generator(QModelIndex)
    :type col_iter: bool
    :type parent_index: QModelIndex
    :type model: QAbstractItemModel
    """
    index = model.index(0, 0, parent_index)

    while True:
        if col_iter:
            for col in range(0, model.columnCount(parent_index)):
                yield index.sibling(index.row(), col)
        else:
            yield index

        if model.rowCount(index) > 0:
            for _ in model_iter(model, index, col_iter):
                yield _

        index = index.sibling(index.row() + 1, index.column())
        if not index.isValid():
            break

使い方は簡単で、モデルを渡すだけでイテレータを返してくれる。

tree_model = QStandardItemModel()

item = QStandardItem("A")
item.appendRow(QStandardItem("A-1"))
item.appendRow(QStandardItem("A-2"))
tree_model.appendRow(item)

item = QStandardItem("B")
item.appendRow(QStandardItem("B-1"))
item.appendRow(QStandardItem("B-2"))
tree_model.appendRow(item)

item = QStandardItem("C")
tree_model.appendRow(item)

print([_.data() for _ in model_iter(tree_model)])
>>> [u'A', u'A-1', u'A-2', u'B', u'B-1', u'B-2', u'C']

ツリー型だけでなく、テーブル型のモデルにも対応している。

table_model = QStandardItemModel(3, 3)
for r in range(3):
    for c in range(3):
        table_model.setItem(r, c, QStandardItem("%d-%d" % (r, c)))

print([_.data() for _ in model_iter(table_model)])
>>> [u'0-0', u'0-1', u'0-2', u'1-0', u'1-1', u'1-2', u'2-0', u'2-1', u'2-2']

逆順イテレータ

ついでに逆順イテレータも作成した。

def model_iter_r(model, parent_index=QModelIndex(), col_iter=True):
    """ モデルのイテレータ(逆順)
    :rtype: generator(QModelIndex)
    :type col_iter: bool
    :type parent_index: QModelIndex
    :type model: QAbstractItemModel
    """
    index = model.index(model.rowCount(parent_index) - 1, 0, parent_index)

    while True:
        if model.rowCount(index) > 0:
            for _ in model_iter_r(model, index, col_iter):
                yield _

        if col_iter:
            for col in range(model.columnCount(parent_index) - 1, -1, -1):
                yield index.sibling(index.row(), col)
        else:
            yield index

        index = index.sibling(index.row() - 1, index.column())
        if not index.isValid():
            break

使い方は、正順のものとまったく同じ。

print([_.data() for _ in model_iter_r(tree_model)])
>>> [u'C', u'B-2', u'B-1', u'B', u'A-2', u'A-1', u'A']

print([_.data() for _ in model_iter_r(table_model)])
>>> [u'2-2', u'2-1', u'2-0', u'1-2', u'1-1', u'1-0', u'0-2', u'0-1', u'0-0']

ちゃんとツリー構造も逆順に辿っている。

モデルの順次アクセスはよく使う機能だが、再帰を使うためいちいち実装するのは面倒である。
この関数をコピペしておけば何かと便利だ。

次回は、この関数を使って検索オブジェクトを作成する。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3