[PySide] TableViewでリソースブラウザの一覧っぽいものをつくるテスト
PySideの Delegateまわりと、Pointerを使用したModelの書き方のおさらいがてら
Mayaで使用するリソースブラウザのリソース一覧を作るテストをしてみました。
とりあえず現状はこんな感じ。
右側が今回作った部分、いずれは画像も出せるようにするつもりですが、とりあえず文字だけ出す感じで。
UI部分のPtyhonは → これ
長いけど、以下コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# -*- coding: utf-8 -*- import sys from PySide import QtCore, QtGui from maya import OpenMayaUI as omUI import shiboken import ui.main_ui as mUI reload(mUI) def getMayaWindow(): ptr = omUI.MQtUtil.mainWindow() if ptr is not None: return shiboken.wrapInstance(long(ptr), QtGui.QMainWindow) class ResourceBrowser(QtGui.QMainWindow): def __init__(self, parent=getMayaWindow()): QtGui.QMainWindow.__init__(self, parent) self.ui = mUI.Ui_MainWindow() self.ui.setupUi(self) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.model = ResourceModel() self.delegate = ResourceBrowserDelegate() self.ui.resourceList.setModel(self.model) self.ui.resourceList.setItemDelegate(self.delegate) self.ui.resourceList.horizontalHeader().setResizeMode(QtGui.QHeaderView.ResizeToContents) self.ui.resourceList.verticalHeader().setResizeMode(QtGui.QHeaderView.ResizeToContents) # Test用Itemをセット items = [] for i in "ABCDEFGHIJKLMNOPQRSTUVW": items.append(ResourceItem(path=i)) self.model.setItem(items) class ResourceItem(object): path = "" thumb = "" def __init__(self, *args, **kwargs): if 'path' in kwargs: self.path = kwargs['path'] if 'thumb'in kwargs: self.thumb = kwargs['thumb'] class ResourceModel(QtCore.QAbstractTableModel): __items = [] column_num = 5 def __init__(self): QtCore.QAbstractTableModel.__init__(self) def columnCount(self, parent=QtCore.QModelIndex()): return self.column_num def rowCount(self, parent=QtCore.QModelIndex()): if len(self.__items) == 0: return 1 else: return int(len(self.__items) / self.column_num) + 1 def setItem(self, items): self.__items = items self.layoutAboutToBeChanged.emit() self.layoutChanged.emit() def index(self, row, column, parent): if not self.hasIndex(row, column, parent=QtCore.QModelIndex()): return QtCore.QModelIndex() index_num = (self.column_num * row) + column if len(self.__items) > index_num: return self.createIndex(row, column, self.__items[index_num]) else: return QtCore.QModelIndex() def data(self, index, role): if not index.isValid(): return QtCore.QModelIndex() item = index.internalPointer() if role == QtCore.Qt.DisplayRole: return item class ResourceBrowserDelegate(QtGui.QStyledItemDelegate): def __init__(self, parent=None): super(ResourceBrowserDelegate, self).__init__(parent) def paint(self, painter, option, index): data = index.data() painter.drawText(option.rect, QtCore.Qt.AlignCenter, data.path) blank = 3 painter.drawRoundRect(option.rect.left() + blank, option.rect.top() + blank, option.rect.width() - (blank * 2), option.rect.height() - (blank * 2)) def sizeHint(self, option, index): return QtCore.QSize(130, 180) |
まずModel。
今回はTableViewを使用してますが、リソースブラウザとかはListで持っておきたいので
データそのものはリスト型で持たせています。
モデルのデータを取得するindex部分で、columnとrowからindexを取得するようにしています。
column_numを変更すれば、タイル状に並べられるようにしています。
indexでセットするアイテムを制御する時は、data関数ではinternalPointer()を使用することで
現在処理をする column row のModelIndexを取得できます。
きちんと計測したわけではないのですが、コレを使用せずに data内で self.__items[row] でデータを
取得しようとするとものすごく遅くなる印象があります。
1 2 3 4 5 6 7 |
def setItem(self, items): self.__items = items self.layoutAboutToBeChanged.emit() self.layoutChanged.emit() |
Itemをセットするときは、 layoutAbout~とlayoutChanged を両方emitします。
layoutAbout~のほうがないと、動くけれども動作がものすごく不安定になります(何故?
Modelにセットする値は、専用のクラスを作成します。
Delegateでこのクラスの値を読み込むので、dataでは DisplayRole でこのクラスオブジェクトを返します。
続いてDelegate。
Delegateは、TableのセルだったりListの1要素だったりの描画やらその他諸々の処理を実装するもの。
それと知らず、Tableの行すべての背景色を変えるとかをDelegate側で行おうとして描画がぶっ壊れてどうにもならん
問題で苦しみました。
DelegateとViewとでどちらでやったらいいんだろう?何が違うんだろう?と思っていたのですが
View全体にわたる描画まわりを書きたい場合はViewのpaint
Cell1つずつの描画を書きたい場合はDelegateのpaint
でやればいいと認識しました。
今回は、1つのセルが1つのアイテム、アイテム単位で見た目を描画したいので
Delegateのpaintで作成します。
option.rect で、1つのCellの矩形を取得できるので、それをベースに色々イイカンジにレイアウトしていきます。
今回は、とりあえずかどが丸い四角と文字を描画してみています。
セルの大きさは、 sizeHint で設定。
この大きさで固定するために
1 2 3 4 |
self.ui.resourceList.horizontalHeader().setResizeMode(QtGui.QHeaderView.ResizeToContents) self.ui.resourceList.verticalHeader().setResizeMode(QtGui.QHeaderView.ResizeToContents) |
Headerサイズではなく、sizeHintの数値を使用するようにします。
D&Dで入れ替えしたいなら、GraphicsViewを使用する方がいい気がしますが
今回みたいにListをタイル状に並べるのなら今回のやり方のほうが良さそうですね。
最近あんまり暇な時間がないので日曜プログラミングが捗らないですが、ちまちま作っていこうズサーc⌒っ゚Д゚)っ