2012-10-14 161 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

相關問題