如何访问存储在QModelIndex中的数据

alp*_*ric 4 python qt pyqt

下面的代码创建了一个单独QListView的数据和代理模型"附加".单击其中一个单选按钮可调用buttonClicked()功能.

此函数调用模型的.data(index,role)方法来获取存储在当前索引中的数据.

对于DisplayRole模型的.data()方法,正确返回索引的名称(在创建时分配给它).但是当使用
'ItemDataRole'时,我收到一个错误:

TypeError: QSortFilterProxyModel.data(QModelIndex, int role=Qt.DisplayRole): argument 2 has unexpected type 'sip.enumtype'
Run Code Online (Sandbox Code Playgroud)

-

Question 1: How to fix this error?
Run Code Online (Sandbox Code Playgroud)

如果你看看addItems()方法,那里有一条线:

self.setData(index, 'keyword')
Run Code Online (Sandbox Code Playgroud)

显然我正在尝试将'keyword'设置为我自己的"自定义数据"(这是过滤索引时将使用的ProxyModel吗?).

问题2:如何查询我设置的字符串"keyword" self.setData(index, 'keyword')?这些数据是可访问的还是"保留"且无法查询?

在此输入图像描述

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 ProxyModel(QtGui.QSortFilterProxyModel):
    def __init__(self, parent=None):
        super(ProxyModel, self).__init__(parent)

class DataModel(QtCore.QAbstractListModel):
    def __init__(self):
        QtCore.QAbstractListModel.__init__(self)
        self.items=[] 
    def rowCount(self, parent=QtCore.QModelIndex()):
        return len(self.items)
    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()]

        elif role==QtCore.Qt.ItemDataRole:
            return index.data()

    def addItems(self):
        for key in elements:
            index=QtCore.QModelIndex()
            self.setData(index, 'keyword')
            self.beginInsertRows(index, 0, 0)
            self.items.append(key)           

        self.endInsertRows()        

class Window(QtGui.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        layout=QtGui.QVBoxLayout()
        self.setLayout(layout)        

        self.view=QtGui.QListView()

        self.dataModel=DataModel()        
        self.dataModel.addItems()

        self.proxyModel=ProxyModel()
        self.proxyModel.setSourceModel(self.dataModel)
        self.view.setModel(self.proxyModel)
        buttonsLayout=QtGui.QHBoxLayout()
        animalsButton=QtGui.QRadioButton('Show Animals')
        birdsButton=QtGui.QRadioButton('Show Birds')
        fishButton=QtGui.QRadioButton('Show Fish')
        self.buttons=[animalsButton,birdsButton,fishButton]
        for button in self.buttons:
            button.toggled.connect(self.buttonClicked)
            buttonsLayout.addWidget(button)      
        layout.addWidget(self.view)
        layout.insertLayout(1,buttonsLayout)
        self.show()

    def buttonClicked(self,arg=None):
        for button in self.buttons:
            if button.isChecked(): break

        index=self.view.currentIndex()
        print 'Index DisplayRole: %s'%self.view.model().data(index, QtCore.Qt.DisplayRole).toString() 
        # print 'ItemDataRole', self.view.model().data(index, QtCore.Qt.ItemDataRole)    

window=Window()
sys.exit(app.exec_())
Run Code Online (Sandbox Code Playgroud)

alp*_*ric 8

下面是关于如何使用工作示例QTableViewQStandardItemModel填充QStandardItem秒.

使用QtGui.QStandardItemModel结束的一个可能的优点QtCore.QAbstractListModelQtGui.QStandardItemModel不必为了被分配而被分类QTableView.你只需要继续宣布它:

view=QtGui.QTableView() # declare table view
model=QtGui.QStandardItemModel() # declare model
view.setModel(model) # assign model to table view
Run Code Online (Sandbox Code Playgroud)

要创建视图项,请先声明它:

item=QtGui.QStandardItem('My Item Name') # stored 'My Item Name' can be queried using `Qt.DisplayRole` flag
Run Code Online (Sandbox Code Playgroud)

QStandardItem使用以下命令分配声明视图:

model.appendRow(item)
Run Code Online (Sandbox Code Playgroud)

model.appendRow(item)方法"创建"与QModelIndex表视图中的列一样多的es.因此,无需为QModelIndex一行中的每个列手动创建es:项目分配给的行.

接下来使用item.setData(value,role)方法,您可以使用预定义QModelIndex角色之一存储任何类型的数据,例如:

item.setData('< Column 0 My Display Value as "DisplayRole" >', QtCore.Qt.DisplayRole)
item.setData('< Column 0 My Custom Value as "UserRole" >', QtCore.Qt.UserRole)
item.setData('< Column 0 My Custom Value as "UserRole+1" >', QtCore.Qt.UserRole+1)
Run Code Online (Sandbox Code Playgroud)

上面的所有三个赋值行都用于为同一个"item"分配三个不同的值:first value是一个'< Column 0 My Display Value as "DisplayRole" >'存储在Qt.DisplayRolerole 下的字符串(使用此角色将其检索回来).

字符串值:'< Column 0 My Custom Value as "UserRole" >'存储在Qt.UserRole.使用此角色将其检索回来.等等.

虽然item.setData(value,role)方法非常有用并且确实使用了简单的语法,但它也非常有限,因为它只处理QModelIndex存储在项目所分配的行的零列中的单个.为了能够存储存储在项目行的非零列中的自定义数据(或修改现有数据),我们首先得到项目的行号:

itemRow=item.row()
Run Code Online (Sandbox Code Playgroud)

知道了项目的行号,我们可以在"手动"模式下使用每列获取所有项目索引:

indexOfColumn1=model.index(itemRow, 1)
indexOfColumn2=model.index(itemRow, 2)
Run Code Online (Sandbox Code Playgroud)

(其中第二个整数参数,例如1或是2列号).

或者采用"全自动"模式:

for i in range(model.columnCount()):
    eachColumnIndex=model.index(itemRow, i)
Run Code Online (Sandbox Code Playgroud)

知道项目QModelIndexes我们可以使用它们来查询或存储数据,就像我们使用item.setData()方法一样(一种只从/向零列分配/转发数据的方法QModelIndex).

为了存储和检索每列中的数据 - QModelIndex我们必须使用model.setData(index,value,role)model.data(index, role)方法(似乎我们无法QModelIndex直接使用实例获取/设置数据...像这样:

myIndex.setData(value,role)- 这是无效的代码,因为QModelIndex没有.setData()方法.

为了检索QModelIndex我们使用的存储数据model.data(index,role):

model=view.model()
print model.data(index, QtCore.Qt.UserRole+1).toPyObject() 
Run Code Online (Sandbox Code Playgroud)

对于单个列视图(例如.QListView)处理提供的QStandardItem方法可能就足够了.但对于多列视图(例如,QTabLeView有可能QModelIndexe必须访问单个列的s.

在此输入图像描述

import os,sys
home=os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
sys.path.append(os.path.join(home,'site-packages'))
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)
class Window(QtGui.QTableView):
    def __init__(self):
        super(Window, self).__init__() 
        model=QtGui.QStandardItemModel()

        model.setHorizontalHeaderLabels(['Column 0','Column 1','Column 3'])
        for i in range(3):
            item=QtGui.QStandardItem('Column 0 Item %s'%i)
            item.setData('< Column 0 Custom Value as "UserRole" >', QtCore.Qt.UserRole)
            item.setData('< Column 0 Custom Value as "UserRole+1" >', QtCore.Qt.UserRole+1)
            model.appendRow(item)

            itemRow=item.row()
            indexOfColumn1=model.index(itemRow, 1)
            indexOfColumn2=model.index(itemRow, 2)

            model.setData(indexOfColumn1, 'Column 1 Item', QtCore.Qt.DisplayRole)
            model.setData(indexOfColumn1, '< Column 1 Custom Value as "UserRole" >', QtCore.Qt.UserRole)

            model.setData(indexOfColumn2, 'Column 2 Item', QtCore.Qt.DisplayRole)
            model.setData(indexOfColumn2, '< Column 2 Custom Value as "UserRole" >', QtCore.Qt.UserRole)

        self.setModel(model)
        self.clicked.connect(self.onClick)  
        self.show()

    def onClick(self,index=None):
        row=index.row()
        column=index.column()

        model=self.model()
        indexOfColumn0=model.index(row, 0)
        indexOfColumn1=model.index(row, 1)
        indexOfColumn2=model.index(row, 2)
        print indexOfColumn0==index, indexOfColumn1==index, indexOfColumn2==index


        print  'ROW: %s  COLUMN: %s'%(row,column)
        print 'DispayRoleData via self.model().data(index,role): "%s"'%self.model().data(index, QtCore.Qt.DisplayRole).toString()
        print 'UserRoleData via self.model().data(index,role): "%s"'%self.model().data(index, QtCore.Qt.UserRole).toPyObject()
        print 'UserRoleData via self.model().data(index,role): "%s"'%self.model().data(index, QtCore.Qt.UserRole+1).toPyObject()      

        for key in self.model().itemData(index):
            print 'self.model.itemData(index):    key: %s  value: %s'%(key, self.model().itemData(index)[key].toString())

        item=self.model().itemFromIndex(index)


window=Window()
sys.exit(app.exec_())
Run Code Online (Sandbox Code Playgroud)