[PySide] QAbstractItemModelを使用したTreeViewのModelを作る

以前にやったAbstractTableModelを使用したやり方だとTreeViewだとエラーでおかしくなったり
動作がえらく重くて微妙だったので、TreeView用のModelを作成するやり方を試してみました。

やりかたは
Pyside – Custom Hierarchical Data Model
QTreeView and QAbractItemModel example
を参考にしました。

とりあえず、長いですが全コードをば。

TreeModelTest

実行結果はこんな感じ。

サンプルはずいぶん前に見つけていたのですが、見てもいまいち理解できず放置してましたが
色々試してようやく意味が分かりました。

まず、全体の構造は大きく分けて3つ

1 表示するデータ構造体用のクラス
2 TreeViewの1行(以降Itemクラスと呼ぶ)をコントロールするクラス
3 AbstractItemModelを継承したModel

今回のサンプルの書き方だと1はいらなかった気もしますがとりあえず参考サイトと同じく
残しておきました。
ポイントとなるのが2。
TreeViewはItemが親子化することができます。
その構造を実現するため、親と子のデータを取得できる構造がこのItemクラスに
実装されています。
で、メインとなるModel。
Modelでは、

  1. rootItemを作成(空のItemクラス)
  2. 表示したいデータを、rootItemの子として登録する
  3. AbstractItemModelのindexとparentをオーラーライドした関数内で2の構造から表示したいデータを取得
  4. internalPointer()で、Itemのクラスオブジェクトを取得し、取得結果をdata関数内のDisplayRoleで返す

ざっくりですが、こんな感じの挙動をしています。

index と parent 関数で columnとrowに対応するItemを指定→internalPointer()で取得というのに
気づくまでだいぶ時間がかかってしまいました。

あと、最後の最後で苦戦したのが描画がおかしくなってしまったこと。
その原因が、 rowCount関数のオーバーライドし忘れでした。

AbstractItemModelを継承する際は、

  • columnCount
  • rowCount
  • parent
  • index

この4つのオーバーライドが必須+ヘッダの表示をしたい場合はheaderData
Count2つは忘れがちなので特に注意です(と、自分に言い聞かせる)

その他今回初めて知ったもの

ModelIndex()の使い方

return QtCore.QModelIndex()

所々↑ような記述とか

if not parent.isValid():

とかが出てくるのがなんだろうと思ったら、

QtCore.QModelIndex の引数がない場合は、 Indexが -1 -1 となって無効な(有効でないIndex)が返される。
isValid() は、 有効なIndexかどうかを判定してくれる関数なので、つまりは

return None

して

if parent is not None:

で判定しているのと同じようなものなのですね。なるほど。

 

とりあえず、書き方自体はもうちょっと改良の余地がありそうですが
AbstractTableModelではなくAbstractItemModelを使用したTreeViewのModelの書き方は理解出来ました。
分かってしまえば楽なんですが、理解するまでが大変だ…
あぁ、もっとコードの読解力が欲しい

コメントを残す

メールアドレスが公開されることはありません。


*