2012-10-14 159 views
1

我在使用我指定的字段中的值对QListView中的项目进行排序时遇到了一些问题。如何使用Qt.UserRole对Qt QListview中的项目进行排序

基本上我想要做的是这样的:

  1. 检测人脸的照片集并在QListView
  2. 集群显示他们的面孔(图片)
  3. 更新视图通过将属于同一群集的列表中的项目(它们是面部图像)放在一起。具体地说,如果项目1,3,5在一个集群中并且项目2,4,6在另一个集群中,那么在显示项目2,4,6中的任何一个之前应该显示项目1,3,5(以任意排列方式)或相反亦然。

我去这样做的方法就是在我的名单到集群标签设置UserRole领域之一每个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() 

回答

1

没有什么错,你发布的代码。所以你如何使用它一定是有问题的。你如何生成集群标签?

下面是使用FacesView类排序,你打算测试脚本:

from random import randint 
from PySide.QtGui import QWidget, QPushButton, QVBoxLayout, QApplication 
from facesview import FacesView 

class Window(QWidget): 
    def __init__(self): 
     QWidget.__init__(self) 
     self.list = FacesView(self) 
     self.button = QPushButton('Test', self) 
     self.button.clicked.connect(self.handleButton) 
     layout = QVBoxLayout(self) 
     layout.addWidget(self.list) 
     layout.addWidget(self.button) 

    def handleButton(self): 
     labels = [] 
     self.list.model().setRowCount(0) 
     for row in range(10): 
      labels.append(randint(0, 3)) 
      text = 'Item(%d) - Cluster(%d)' % (row, labels[-1]) 
      self.list.addItem(text, 'icon.png') 
     self.list.updateFaceClusters(labels) 

if __name__ == '__main__': 

    import sys 
    app = QApplication(sys.argv) 
    window = Window() 
    window.show() 
    sys.exit(app.exec_()) 
+0

嗨。首先,感谢您的回复。我已经尝试过你的测试代码,并且实际上FacesView类的排序工作。我通过在每个脸部图标的文本标签中显示群集标签来跟踪您的示例,看起来群集正确执行,但具有相同群集标签的项目仍然不相邻。 – lightalchemist

+0

我怀疑排序不起作用,因为我如何配置我的列表。 FacesView的viewMode属性最初设置为IconMode,其移动属性设置为静态。将viewMode更改为ListMode和移动到Snap并没有帮助。任何想法我应该检查哪些属性?谢谢。 – lightalchemist

+0

嗨,我想通了。你是对的,问题在于标签,特别是标签的“类型”。我从一个库中获得了集群标签,它们将它们作为一个dtype = int32的numpy数组返回。由于某些原因,即使代码能够使用其中的值来更新文本标签和CLUSTER_ROLE字段,也无法使用它们对元素进行排序。如果我使用“labels.tolist()”将numpy数组转换为列表或使用“labels = map(int,labels”)将元素映射到整数,则排序工作。谢谢! – lightalchemist

相关问题