2014-09-17 8 views
0

Код ниже создает окно с QListView (слева) и QTableView (справа). Оба представления используют одну и ту же модель данных.Как работает QSortFilterProxyModel

QListView перечисляет ключи словаря, такие как «Животные», «Рыба» и «Птицы». Когда щелкнул элемент «Животные» в левом боку, справа должно отображаться: первый столбец: «Bison», второй столбец: «Panther» и третий: «Elephant».

Для решения этой задачи было определено, что QSortFilterProxyModel присвоен праву QTableView, чтобы отфильтровать его контекст. Каждый щелчок мыши выполняется с помощью левого QListView триггеров onClick(). Эта функция проверяет текущий элемент текущего вида в левом. Затем он запрашивает имя ключа и соответствующее значение ключа от словаря self.modelDict.

Вот скриншот окна: enter image description here

Видимо код не делать то, что он должен. QSortFilterProxyModel действительно отображает правильный «элемент» ... так что оба представления синхронизированы. Это хорошо. Но в правом столбце отображается одно и то же ключевое имя в каждом столбце: «Животные», «Животные», «Животные». Хотя цель еще раз, чтобы отобразить список самих животных, взятых из словаря, полученного от .data() метода:

value=self.dataModel.data(index, QtCore.Qt.ItemDataRole) 

где значение является словарем, такие как:

{1:'Bison',2:'Panther',3:'Elephant'} 

Пожалуйста посоветуйте.

import os,sys 
from PyQt4 import QtCore, QtGui 
app=QtGui.QApplication(sys.argv) 
elements={'Animals':{1:'Bison',2:'Panther',3:'Elephant'},'Birds':{1:'Duck',2:'Hawk',3:'Pigeon'},'Fish':{1:'Shark',2:'Salmon',3:'Piranha'}} 

class DataModel(QtCore.QAbstractTableModel): 
    def __init__(self): 
     QtCore.QAbstractTableModel.__init__(self) 
     self.modelDict={}  
     self.items=[]  
    def rowCount(self, parent=QtCore.QModelIndex()): 
     return len(self.items) 
    def columnCount(self, index=QtCore.QModelIndex()): 
     return 3 
    def data(self, index, role): 
     if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant() 
     if role==QtCore.Qt.DisplayRole: return self.items[index.row()] 
     if role==QtCore.Qt.ItemDataRole: return self.modelDict.get(str(index.data().toString())) 

    def addItem(self, itemName=None, column=0): 
     totalItems=self.rowCount()+1 
     self.beginInsertRows(QtCore.QModelIndex(), totalItems, column) 
     if not itemName:   itemName='Item %s'%self.rowCount() 
     self.items.append(itemName) 
     self.endInsertRows() 

    def buildItems(self): 
     for key in self.modelDict: 
      index=QtCore.QModelIndex() 
      self.addItem(key) 

class ProxyModel(QtGui.QSortFilterProxyModel): 
    def __init__(self, parent=None): 
     super(ProxyModel, self).__init__(parent) 

class Window(QtGui.QWidget): 
    def __init__(self): 
     super(Window, self).__init__() 
     mainLayout=QtGui.QHBoxLayout() 
     self.setLayout(mainLayout) 

     self.dataModel=DataModel() 
     self.dataModel.modelDict=elements 
     self.dataModel.buildItems() 

     self.proxyModel=ProxyModel() 
     self.proxyModel.setFilterKeyColumn(0)  
     self.proxyModel.setSourceModel(self.dataModel) 

     self.viewA=QtGui.QListView() 
     self.viewA.setModel(self.dataModel) 
     self.viewA.clicked.connect(self.onClick)   
     self.viewB=QtGui.QTableView() 
     self.viewB.setModel(self.proxyModel) 

     mainLayout.addWidget(self.viewA) 
     mainLayout.addWidget(self.viewB)  
     self.show() 

    def onClick(self): 
     index=self.viewA.currentIndex() 
     key=self.dataModel.data(index, QtCore.Qt.DisplayRole) 
     value=self.dataModel.data(index, QtCore.Qt.ItemDataRole)   
     self.proxyModel.setFilterRegExp('%s'%key) 
     print 'onClick(): key: %s'%type('%s'%key) 

window=Window() 
sys.exit(app.exec_()) 
+1

QSortFilterModel предназначен для выбора подмножества одних и тех же элементов из модели - вы не должны удивляться тому, что у вас есть те же слова, что и в обоих представлениях. – mdurant

+0

Находится довольно хорошо pyside-example: site: https: //qt.gitorious.org/pyside/pyside-examples/raw/060dca8e4b82f301dfb33a7182767eaf8ad3d024: examples/itemviews/basicsortfiltermodel.py – alphanumeric

ответ

1

DisplayRole должен возвращать разные данные для разных строк.
Accodring к коду:

Если data вызывается с index(1,0) он возвращает Animals.
Если data вызывается с index(1,1), он возвращает Animals.
Если data вызывается с index(1,2), он возвращает Animals.

Вместо этого он должен быть

Если data вызывается с index(1,0) он возвращает Animals.
Если data вызывается с index(1,1), он возвращает Bison.
Если data вызывается с index(1,2), он возвращает Panther.
Если data вызывается с index(1,3), он возвращает Elephant.
Всего 4 столбца.

Чтобы скрыть первый столбец, который является именем группы из таблицы, используйте hideColumn(0).

пс. ItemDataRole - это имя перечисления не значение.

+0

Спасибо! Я не понимал, что вся «работа» должна выполняться внутри метода «DataModel.data» (заполняя модель индексами). Я думал, что мне придется настроить «ProxyModel», чтобы разобраться. Что может быть опасно, так это то, что номера строк и столбцов индекса должны поддерживаться синхронно с структурой переменных данных (здесь 'self.modelDict'). Я также не уверен, что разработка модели для виджета с несколькими видами является хорошей идеей ... Еще раз спасибо! – alphanumeric

+0

Добро пожаловать. При проектировании представления модели это обычная работа по синхронизации данных модели (количество строк, количество столбцов, текст ...) с хранилищем данных. Обычно это также делается с использованием сигнальных слотов. Если вы хотите сохранить данные в модели, вы должны избегать изменения данных вне модели. Когда данные изменяются, не забывайте «испускать dataChanged», когда текст ячейки изменяется, «rowsAboutToBeInserted», «rowsInserted» при добавлении строк, «rowsAboutToBeRemoved», «rowsRemoved» при удалении строк. – Ezee

+0

Я прочитал кратко о 'self.emit (SIGNAL (« dataChanged (QModelIndex, QModelIndex) »), index, index)' используется в 'model.setData()'. Но что такое зарезервированная цель 'rowsAboutToBeInserted, rowsInserted, rowsAboutToBeRemoved, rowsRemoved' слоты? Почему 'self.beginInsertRows (QtCore.QModelIndex(), totalItems, столбец); self.items.append (itemName); self.endInsertRows() 'нельзя использовать исключительно и использовать в каждой ситуации при добавлении строки? – alphanumeric

Смежные вопросы