QListView
指定したフィールドの値を使用して、アイテムの並べ替えに問題があります。
基本的に私がやろうとしていることはこれです:
- 写真のコレクションから顔を検出し、
QListView
- 顔をクラスター化する(画像)
- 同じクラスターに属するアイテム(顔画像)を一緒にリストに配置して、ビューを更新します。具体的には、アイテム1、3、5が1つのクラスターにあり、アイテム2、4、6が別のクラスターにある場合、アイテム2、4、6のいずれかが表示される前に、アイテム1、3、5が(任意の順列で)表示される必要があります。またはその逆。
UserRole
これを行う方法は、リスト内の各フィールドの1つをQStandardItem
クラスターラベルにQStandardModel
設定してから、これに従ってソートするようにすることUserRole
です。これにより、同じクラスター内のアイテム(つまり、内の同じクラスターラベルを持つアイテムUserRole
)が隣り合って表示されます。
アイテムを正常に設定することはできますが、並べ替えの役割をデフォルト(つまり、各面のテキストラベルに従って並べ替える)に設定した場合でもUserRole
、で並べ替え関数を呼び出してQStandardModel
もアイテムは並べ替えられませんでした。DisplayRole
意図されました。
誰かが私のコードの何が問題になっているのか教えてもらえますか、または別の方法を提供できますか?ソートリストをグーグルで検索したところ、 QSortFilterProxyModelで次のリンクが見つかりましたが、Qtを初めて使用するため、状況に適応させることができません。
返信をよろしくお願いします。
関連するコードは次のとおりです。
import os
from PySide.QtGui import QListView, QStandardItemModel, QStandardItem, QIcon
from PySide.QtCore import Qt
class FacesView(QListView):
"""
View to display detected faces for user to see and label.
"""
UNCLUSTERED_LABEL = -1
CLUSTER_ROLE = Qt.UserRole + 1
def __init__(self, *args):
super(FacesView, self).__init__(*args)
self._dataModel = QStandardItemModel()
self.setModel(self._dataModel)
# Layout items in batches instead of waiting for all items to be
# loaded before user is allowed to interact with them.
self.setLayoutMode(QListView.Batched)
def updateFaceClusters(self, labels):
"""Update the cluster label for each face.
@param labels: [1 x N] array where each element is an integer
for the cluster the face belongs to."""
assert(len(labels) == self._dataModel.rowCount())
# Put the cluster label each item/face belong to in the
# CLUSTER_ROLE field.
for i in xrange(self._dataModel.rowCount()):
index = self._dataModel.index(i, 0)
self._dataModel.setData(index, labels[i], self.CLUSTER_ROLE)
# Use cluster label as sort role
self._dataModel.setSortRole(self.CLUSTER_ROLE)
# This does NOT seem to sort the items even though it works fine
# when sort role is the default Qt.DisplayRole.
self._dataModel.sort(0)
print("Finished updating face clusters")
def itemsInList(self):
"""Returns the label for a face and the path to its image.
@return: (label, path)"""
items = []
for i in xrange(self._dataModel.rowCount()):
label = self._dataModel.index(i, 0).data(Qt.DisplayRole)
imagePath = self._dataModel.index(i, 0).data(Qt.UserRole)
clusterLabel = self._dataModel.index(i, 0).data(self.CLUSTER_ROLE)
items.append((imagePath, label, clusterLabel))
return items
def addItem(self, label, imagePath):
"""Add an item to list view
@param label: The label associated with the item.
@param imagePath: Path to image for the icon."""
if os.path.exists(imagePath):
icon = QIcon(imagePath)
else:
icon = QIcon(':/res/Unknown-person.gif')
item = QStandardItem(icon, label)
item.setEditable(True)
# Add image path to the UserRole field.
item.setData(imagePath, Qt.UserRole)
# Add cluster label to image. CLUSTER_ROLE is where I intend
# to put the item's cluster label.
item.setData(self.UNCLUSTERED_LABEL, self.CLUSTER_ROLE)
# Prevent an item from dropping into another item.
item.setDropEnabled(False)
# Add item to list indirectly by adding it to the model.
self._dataModel.appendRow(item)
def clear(self):
self._dataModel.clear()