How to access data stored in QModelIndex

2024/11/13 15:25:05

The code below create a single QListView with the data and proxy models "attached". Clicking one of the radio buttons calls for buttonClicked() function.

This function calls model's .data(index,role) method to get the data stored in a current index.

For the DisplayRole the model's .data() method properly returns the name of index (assigned to it by the time it was created). But when
'ItemDataRole' is used I am getting an error:

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

--

Question 1: How to fix this error?

If you take a look at addItems() method there is a line there:

self.setData(index, 'keyword')

Apparently I am trying to set 'keyword' as my own "custom data" (is it what ProxyModel is going to be use while filtering the indexes?).

Question 2: How to query the string "keyword" I've set with self.setData(index, 'keyword')? Is this data accessible or it is "reserved" and can't be queried?

enter image description here

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(): breakindex=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_())
Answer

Here is a working example on how to use QTableView with QStandardItemModel populated with QStandardItems.

A possible advantage of using QtGui.QStandardItemModel over QtCore.QAbstractListModel is that QtGui.QStandardItemModel doesn't have to be sub-classed in order to be assigned to QTableView. You just go ahead and declare it:

view=QtGui.QTableView() # declare table view
model=QtGui.QStandardItemModel() # declare model
view.setModel(model) # assign model to table view

To create a view-item declare it first:

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

Assign a declared QStandardItem to view using:

model.appendRow(item)

model.appendRow(item) method "creates" as many QModelIndexes as there are columns in a table-view. So there is no need to create QModelIndexes manually for each column in a row : the row the item was assigned to.

Next using item.setData(value,role) method you can store any type of data using one of pre-defined QModelIndex roles such as:

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)

All three assignment-lines above are used to assign three different values to the same "item": first value is a string '< Column 0 My Display Value as "DisplayRole" >' which is stored under Qt.DisplayRole role (use this role to retrieve it back).

A string value: '< Column 0 My Custom Value as "UserRole" >' is stored under Qt.UserRole. Use this role to retrieve it back. And etc.

While item.setData(value,role) method is quite useful and it does use a simple syntax it is also very limited since it only deals with a single QModelIndex stored in a zero column of the row the item is assigned to. In order to be able to store a custom data (or modify an existing data) stored in non-zero columns of the item's row we get the item's row number first:

itemRow=item.row()

Knowing the item's row-number we can get all the item indexes from every column using in a "manual" mode:

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

(where a second integer argument such as 1 or 2 are the column numbers).

Or in a "fully automatic" mode:

for i in range(model.columnCount()):eachColumnIndex=model.index(itemRow, i)

Knowing the item's QModelIndexes we can use them to query or store data just like we did using item.setData() method (a method that only assigns/retreives a data from/to a zero-column QModelIndex).

In order to store and retreive the data in each-column-QModelIndex we have to use model.setData(index,value,role) and model.data(index, role) methods (it appears we can't get/set the data using QModelIndex instance directly... like this:

myIndex.setData(value,role) - this is invalid code since QModelIndex doesn't come with .setData() method.

In order to retrieve the data stored per QModelIndex we use model.data(index,role):

model=view.model()
print model.data(index, QtCore.Qt.UserRole+1).toPyObject() 

For a single column views (such as .QListView) dealing with supplied QStandardItem methods would be probably sufficient. But for multi-column views (such as QTabLeView there is a chance the individual column's QModelIndexes would have to be accessed.

enter image description here

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==indexprint  '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_())
https://en.xdnf.cn/q/72057.html

Related Q&A

Pythons read and write add \x00 to the file

I have come across a weird problem when working with files in python. Lets say I have a text file and a simple piece of code that reads the contents of the file and then rewrites it with unaltered cont…

NetworkX remove attributes from a specific node

I am having a problem with networkX library in python. I build a graph that initialises some nodes, edges with attributes. I also developed a method that will dynamic add a specific attribute with a sp…

How to use Python left outer join using FOR/LIST/DICTIONARY comprehensions (not SQL)?

I have two tuples, details below:t1 = [ [aa], [ff], [er] ]t2 = [ [aa, 11,], [er, 99,] ]and I would like to get results like these below using python method similar to SQLs LEFT OUTER JOIN:res = [ [aa, …

GaussianMixture initialization using component parameters - sklearn

I want to use sklearn.mixture.GaussianMixture to store a gaussian mixture model so that I can later use it to generate samples or a value at a sample point using score_samples method. Here is an exampl…

How to use geopy vicenty distance over dataframe columns?

I have a dataframe with location column which contains lat,long location as followsdeviceid location 1102ADb75 [12.9404578177, 77.5548244743]How to get the di…

Opening a postgres connection in psycopg2 causes python to crash

Im getting the following error message when I try to open up a connection to a postgres database. Perhaps its related to OpenSSL, but I cant understand the error message. Can anyone help?>>>…

Calling generated `__init__` in custom `__init__` override on dataclass

Currently I have something like this: @dataclass(frozen=True) class MyClass:a: strb: strc: strd: Dict[str, str]...which is all well and good except dicts are mutable, so I cant use my class to key anot…

Python Watchdog process existing files on startup

I have a simple Watchdog and Queue process to monitor files in a directory. Code taken from https://camcairns.github.io/python/2017/09/06/python_watchdog_jobs_queue.htmlimport time from watchdog.events…

Updating Text In Entry (Tkinter)

The piece of code below takes input from user through a form and then returns the input as multiplied by 2. What I want to do is, when a user types a number (for example 5) and presses the "Enter&…

Python prevent overflow errors while handling large floating point numbers and integers

I am working on a python program to calculate numbers in the Fibonacci sequence. Here is my code:import math def F(n):return ((1+math.sqrt(5))**n-(1-math.sqrt(5))**n)/(2**n*math.sqrt(5)) def fib(n):for…