The code below creates a single QListView with model. Clicking its item deletes it from the model. But QListView still reports that the number of model's items remains unchanged (like there were no items deleted). Is there any way to fix it?
class Model(QtCore.QAbstractListModel):
def __init__(self):
QtCore.QAbstractListModel.__init__(self)
self.items=[]
self.modelDict={}
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.modelDict)
def data(self, index, role):
if not index.isValid():
return QtCore.QVariant()
if not (0 <= index.row() < len(self.items)):
return QtCore.QVariant()
if not index.isValid():
return QtCore.QVariant()
if role==QtCore.Qt.ItemDataRole:
key=str(index.data().toString())
returnedValue=self.modelDict.get(key)
return QtCore.QVariant(returnedValue)
elif role==QtCore.Qt.DisplayRole:
row=index.row()
itemTitle=self.items[row]
return QtCore.QVariant(itemTitle)
def addItems(self):
for key in self.modelDict:
index=QtCore.QModelIndex()
self.beginInsertRows(index, 0, 0)
self.items.append(key)
inst=self.modelDict.get(key)
self.setData(index, QtCore.QVariant(inst), QtCore.Qt.DisplayRole)
self.endInsertRows()
def removeByIndex(self, index):
if not index.isValid(): return
row=index.row()
self.beginRemoveRows(QtCore.QModelIndex(), row, 0)
self.items=self.items[:row]+self.items[row+1:]
self.endRemoveRows()
class ListView(QtGui.QListView):
def __init__(self):
super(ListView, self).__init__()
self.model= Model()
self.model.modelDict=elements
self.model.addItems()
self.setModel(self.model)
self.clicked.connect(self.itemClicked)
self.show()
def itemClicked(self, index):
print 'NUMBER OF ITEMS BEFORE DELETE: %s'%self.model.rowCount()
self.model.removeByIndex(index)
print 'NUMBER OF ITEMS AFTER DELETE: %s'%self.model.rowCount()
window=ListView()
sys.exit(app.exec_())
Fully working example on how to delete items from model.
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 Model(QtCore.QAbstractListModel):
def __init__(self):
QtCore.QAbstractListModel.__init__(self)
self.items=[]
self.modelDict={}
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def data(self, index, role):
if not index.isValid():
return QtCore.QVariant()
if not (0 <= index.row() < len(self.items)):
return QtCore.QVariant()
if not index.isValid():
return QtCore.QVariant()
if role==QtCore.Qt.ItemDataRole:
key=str(index.data().toString())
returnedValue=self.modelDict.get(key)
return QtCore.QVariant(returnedValue)
elif role==QtCore.Qt.DisplayRole:
row=index.row()
itemTitle=self.items[row]
return QtCore.QVariant(itemTitle)
def addItems(self):
for key in self.modelDict:
index=QtCore.QModelIndex()
self.beginInsertRows(index, 0, 0)
self.items.append(key)
inst=self.modelDict.get(key)
self.setData(index, QtCore.QVariant(inst), QtCore.Qt.DisplayRole)
self.endInsertRows()
def removeByIndex(self, index):
if not index.isValid(): return
row=index.row()
self.beginRemoveRows(QtCore.QModelIndex(), row, 0)
self.items=self.items[:row]+self.items[row+1:]
key=str(index.data().toString())
if self.modelDict.get(key): self.modelDict.pop(key,None)
self.endRemoveRows()
class ListView(QtGui.QListView):
def __init__(self):
super(ListView, self).__init__()
self.model= Model()
self.model.modelDict=elements
self.model.addItems()
self.setModel(self.model)
self.clicked.connect(self.itemClicked)
self.show()
def itemClicked(self, index):
print 'NUMBER OF ITEMS BEFORE DELETE: %s'%self.model.rowCount()
self.model.removeByIndex(index)
print 'NUMBER OF ITEMS AFTER DELETE: %s'%self.model.rowCount()
window=ListView()
sys.exit(app.exec_())
Related
I'm trying to add custom widget (image below) as item delegate in QTreeview. I do see the size of the treeItem getting bigger but my widget does not show up. Not sure what am I missing here. Thanks in advance for all your suggestions.
Custom Widget
Here is the code
ItemNode (node for QAbstractTeeModel)
class BaseNode:
def __init__(self, data, parent=None):
self._data = data
self._children = list()
self._parent = None
if parent:
parent.addChild(self)
def addChild(self, node):
self._children.append(node)
node._parent = self
def insertChildren(self, position, children):
if position < 0:
return False
for child in children:
child._parent = self
self._children.insert(position, child)
return True
def removeChildren(self, position, count):
if position < 0 or position > len(self._children):
return False
for i in range(count):
child = self._children.pop(position)
child._parent = None
return True
def child(self, row):
if row < self.rowCount():
return self._children[row]
def rowCount(self):
return len(self._children)
def columnCount(self):
return len(self._data)
def parent(self):
return self._parent
def index(self):
if self._parent:
return self._parent._children.index(self)
return 0
def data(self, column):
return self._data[column]
QAbstractItemModel
class NodeModel(QtCore.QAbstractItemModel):
def __init__(self, parent=None):
super().__init__(parent)
self.headers = ["Node"]
self.root_node = BaseNode(["root"])
def getNode(self, index):
if index.isValid():
node = index.internalPointer()
if node:
return node
return self.root_node
def rowCount(self, parent=QtCore.QModelIndex()):
return self.root_node.rowCount()
def columnCount(self, parent=QtCore.QModelIndex()):
return self.root_node.columnCount()
def data(self, index, role):
if not index.isValid():
return
node = self.getNode(index)
if role == QtCore.Qt.EditRole or role == QtCore.Qt.EditRole:
return node
def headerData(self, section, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return self.headers[section]
def flags(self, index):
flgs = 0
if index.isValid():
flgs = QtCore.Qt.ItemIsEditable
flgs |= QtCore.Qt.ItemIsEnabled
flgs |= QtCore.Qt.DisplayRole
return flgs
def parent(self, child):
node = self.getNode(child)
parent = node.parent()
if parent == self.root_node:
return QtCore.QModelIndex()
return self.createIndex(parent.index(), 0, parent)
def index(self, row, column, parent):
parent = self.getNode(parent)
child = parent.child(row)
if child:
return self.createIndex(row, column, child)
return QtCore.QModelIndex()
def insertRows(self, row, count, parent=QtCore.QModelIndex(), children=None):
parent_node = self.getNode(parent)
self.beginInsertRows(parent, row, row + count - 1)
result = parent_node.insertChildren(row, children)
self.endInsertRows()
return result
def removeRows(self, row, count, parent=QtCore.QModelIndex()):
parent_node = self.getNode(parent)
self.beginRemoveRows(parent, row, row + count - 1)
success = parent_node.removeChildren(row, count)
self.endRemoveRows()
return success
ItemEditor (QWidget for Item Delegate
class ItemEditor(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_Form() # this is a UI containing
self.ui.setupUi(self)
self.setAutoFillBackground(True)
Item Delegate
class NodeDelegate(QStyledItemDelegate):
def __init__(self, parent=None):
super().__init__(parent)
def createEditor(self, parent, option, index):
if index.column() == 0:
editor = ItemEditor()
return editor
else:
return super().createEditor(self, parent, option, index)
def setEditorData(self, editor, index):
if index.column() == 0:
pass
else:
return super().setEditorData(editor, index)
def setModelData(self, editor, model, index):
if index.column() == 0:
pass
else:
super().setModelData(editor, model, index)
def sizeHint(self, option, index):
editor = ItemEditor()
return editor.sizeHint()
def updateEditorGeometry(self, editor, option, index):
editor.setGeometry(option.rect)
Implementation in TreeView
app = QtWidgets.QApplication([])
tw = QtWidgets.QTreeView()
model = NodeModel()
tw.setModel(model)
for i in "abcd":
print(i)
node = BaseNode(data=[i])
index = model.index(model.root_node.rowCount(), 0, QtCore.QModelIndex())
model.insertRows(1, 1, index, children=[node])
item_delegate = NodeDelegate()
tw.setItemDelegateForRow(0, item_delegate)
tw.show()
app.exec_()
I'm starting be more an more confused. I cannot make a QTableView emit its signal like I would like. I reduced my case to something less messy, and even in that case I cannot get any signals to be fired when I click.
For example in that code the slot "onClickedRow" is called once when starting the app (I don't know why), but then I can click as much as I want anywhere and the slot is never called :
import sys
from PySide2 import QtWidgets, QtCore, QtGui
class Message(QtCore.QAbstractItemModel):
def __init__(self):
super().__init__()
self.messageList = []
def addMessage(self, typeName, data):
self.messageList.append({"type": typeName,
"data": data})
def data(self, index, role):
if not index.isValid():
return None
if role != QtCore.Qt.DisplayRole:
return None
item = self.messageList[index.row()]
if index.column() == 0:
return str(item["type"])
else:
return str(item["data"])
def headerData(self, section, orientation, role):
if orientation == QtCore.Qt.Horizontal:
if role == QtCore.Qt.DisplayRole:
if section == 0:
return "type"
else:
return "data"
return None
def parent(self, index):
if not index.isValid():
return QtCore.QModelIndex()
return QtCore.QModelIndex()
def index(self, row, column, parent):
if not self.hasIndex(row, column, parent):
return QtCore.QModelIndex()
else:
return self.createIndex(row, column)
def flags(self, index):
if not index.isValid():
return QtCore.Qt.NoItemFlags
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
def columnCount(self, parent):
return 2
def rowCount(self, parent):
return len(self.messageList)
class FormMessageJournal(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.layout = QtWidgets.QVBoxLayout()
self.messageTable = QtWidgets.QTableView(self)
self.messageTable.clicked.connect(self.onClickedRow())
self.messageList = Message()
self.messageList.addMessage("Send", "Hello")
self.messageList.addMessage("Send", "Hello")
self.messageList.addMessage("Send", "Hello")
self.messageList.addMessage("Send", "Hello")
self.messageTable.setModel(self.messageList)
self.layout.addWidget(self.messageTable)
self.setLayout(self.layout)
def onClickedRow(self, index=None):
print("Click !")
if __name__ == "__main__":
app = QtWidgets.QApplication([])
widget = FormMessageJournal()
widget.show()
sys.exit(app.exec_())
Am I the only one having that type of issues?
self.messageTable.clicked.connect(self.onClickedRow())
Change to:
self.messageTable.clicked.connect(self.onClickedRow)
I attempt to filter self.items's objects by their self.category attribute all from inside of QAbstractTableModel's data() method by comparing this attribute agains a text currently displayed in the QComboBox. Yet, the code doesn't function properly.
Shouldn't be QAbstractTableModel's data() method used "as a substitute to proxy model's accepts row() method?
Is it be possible to achieve the filtering without using QSortFilterProxyModel? If we have to use proxy to filter the model items what would be most Pythonic way of doing this?
from PySide import QtGui, QtCore
class Item(object):
def __init__(self):
self.ID=None
self.name=None
self.category=None
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.items = []
self.filterCategory = None
def rowCount(self, parent=QtCore.QModelIndex()):
return len( [item for item in self.items if item.category==self.filterCategory] )
def columnCount(self, parent=QtCore.QModelIndex()):
return 1
def data(self, index, role):
if not index.isValid(): return
row=index.row()
item=self.items[row]
if item.category!=self.filterCategory:
return
if role == QtCore.Qt.DisplayRole:
return self.items[row].name
if role == QtCore.Qt.UserRole:
return self.items[row]
def insertRows(self, row, item, column=1, index=QtCore.QModelIndex()):
self.beginInsertRows(QtCore.QModelIndex(), row, row+1)
self.items.append(item)
self.endInsertRows()
def setFilter(self, comboText):
self.filterCategory = comboText
self.layoutChanged.emit()
def filterAcceptsRow(self, row, proc):
index=self.sourceModel().index(row, 0, proc)
item=self.sourceModel().data(index, QtCore.Qt.UserRole)
if not item: return True
resourceType=item.category
if self.filters.get(category)==False:
return False
if self.searchText and len(self.searchText)>0 and item.searchString(self.searchText)==False:
return False
return True
class MyWindow(QtGui.QWidget):
def __init__(self, *args):
QtGui.QWidget.__init__(self, *args)
vLayout=QtGui.QVBoxLayout(self)
self.setLayout(vLayout)
self.tableModel = TableModel()
self.ViewA=QtGui.QTableView(self)
self.ViewA.clicked.connect(self.viewClicked)
vLayout.addWidget(self.ViewA)
for row in range(5):
item=Item()
item.ID=row
if item.ID%2: item.category='Pet'
else: item.category='Birds'
item.name='%s_%s'%(item.category, row)
self.tableModel.insertRows(row, item)
self.ViewA.setModel(self.tableModel)
self.combo=QtGui.QComboBox()
self.combo.addItems(['Pet','Birds'])
self.combo.activated.connect(self.comboActivated)
vLayout.addWidget(self.combo)
currentComboCategory=self.combo.currentText()
self.tableModel.setFilter(currentComboCategory)
def viewClicked(self, indexClicked):
print('indexClicked() row: %s column: %s'%(indexClicked.row(), indexClicked.column() ))
def comboActivated(self, arg=None):
comboText=self.combo.currentText()
self.tableModel.setFilter(comboText)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
"no-more-proxy" code below shows how to sort and filter from inside of QAbstractTableModel instead of proxy:
import sys, os
from PyQt import QtGui, QtCore
class Item(object):
def __init__(self,ID=None,name=None,category=None,area=None):
self.ID=ID
self.name=name
self.category=category
self.area='South'
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.currentItems=[]
self.items = []
self.filterCategory = None
self.searchField = None
self.mainColumn=0
self.order=QtCore.Qt.SortOrder.DescendingOrder
def rowCount(self, parent=QtCore.QModelIndex()):
return len( self.currentItems )
def columnCount(self, parent=QtCore.QModelIndex()):
return 5
def data(self, index, role):
if not index.isValid(): return
row=index.row()
column=index.column()
item=self.currentItems[row]
if role == QtCore.Qt.DisplayRole:
if column==0: return item.ID
elif column==1: return item.name
elif column==2: return item.category
elif column==4 or column==5: return item.area
if role == QtCore.Qt.UserRole:
return item
def insertRows(self, row, item, column=1, index=QtCore.QModelIndex()):
self.beginInsertRows(QtCore.QModelIndex(), row, row+1)
self.items.append(item)
self.endInsertRows()
def setFilter(self, comboText=None, searchText=None, mainColumn=None, order=None):
if comboText: self.filterCategory=comboText
if searchText: self.searchText=searchText
if mainColumn!=None: self.mainColumn=mainColumn
self.order=order
self.currentItems=[item for item in self.items if item.category==self.filterCategory]
if searchText:
self.currentItems=[item for item in self.currentItems if searchText in '%s%s%s'%(item.ID, item.name, item.category)]
values=[]
if self.mainColumn==0: values=[[item.ID, item, False] for item in self.currentItems]
elif self.mainColumn==1: values=[[item.name, item, False] for item in self.currentItems]
elif self.mainColumn==2: values=[[item.category, item, False] for item in self.currentItems]
elif self.mainColumn==3 or self.mainColumn==4: values=[[item.area, item, False] for item in self.currentItems]
keys=sorted([value[0] for value in values if isinstance(value, list)])
if self.order==QtCore.Qt.AscendingOrder: keys=list(reversed(keys))
filtered=[]
for key in keys:
for each in values:
if each[0]!=key: continue
if each[2]==True: continue
item=each[1]
filtered.append(item)
each[2]=True
if filtered: self.currentItems=filtered
self.layoutChanged.emit()
class ItemDelegate(QtGui.QItemDelegate):
def __init__(self, parent):
QtGui.QItemDelegate.__init__(self, parent)
def flags(self, index):
if (index.column() == 1):
return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled
else:
return QtCore.Qt.ItemIsEnabled
def createEditor(self, parent, option, index):
tableView=parent.parent()
model=tableView.model()
item=model.data(index, QtCore.Qt.UserRole)
combo=QtGui.QComboBox(parent)
combo.addItems(['South','West','North','East'])
combo.currentIndexChanged.connect(self.comboIndexChanged)
if item.area:
comboIndex=combo.findText(item.area)
if comboIndex>=0:
combo.setCurrentIndex(comboIndex)
else: combo.setCurrentIndex(0)
return combo
def comboIndexChanged(self):
self.commitData.emit(self.sender())
def setModelData(self, combo, model, index):
item=model.data(index, QtCore.Qt.UserRole)
comboText=combo.currentText()
item.area=comboText
class MyWindow(QtGui.QWidget):
def __init__(self, *args):
QtGui.QWidget.__init__(self, *args)
vLayout=QtGui.QVBoxLayout(self)
self.setLayout(vLayout)
self.tableModel = TableModel()
self.searchLine=QtGui.QLineEdit()
vLayout.addWidget(self.searchLine)
self.searchLine.textEdited.connect(self.searchLineEditied)
self.searchLine.returnPressed.connect(self.searchLineEditied)
self.tableView=QtGui.QTableView(self)
self.tableView.setSortingEnabled(True)
self.tableView.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
self.tableView.setShowGrid(False)
self.tableView.setSelectionBehavior(QtGui.QTableView.SelectRows)
self.tableView.setAlternatingRowColors(True)
self.delegate=ItemDelegate(self.tableView)
self.tableView.setItemDelegate(self.delegate)
self.tableView.clicked.connect(self.viewClicked)
vLayout.addWidget(self.tableView)
for row in range(15):
if row%2: category='Pet'
else: category='Birds'
item=Item(category=category, ID=row, name='%s_%s'%(category,row))
self.tableModel.insertRows(row, item)
self.tableView.setModel(self.tableModel)
self.combo=QtGui.QComboBox()
self.combo.addItems(['Pet','Birds'])
self.combo.activated.connect(self.comboActivated)
vLayout.addWidget(self.combo)
currentComboCategory=self.combo.currentText()
self.tableModel.setFilter(currentComboCategory)
self.horizontalHeader=self.tableView.horizontalHeader()
self.horizontalHeader.sortIndicatorChanged.connect(self.headerTriggered)
self.addComboDelegates()
def headerTriggered(self, mainColumn=None, order=None):
self.tableModel.setFilter(mainColumn=mainColumn, order=order)
self.deleteComboDelegates()
self.addComboDelegates()
def comboActivated(self, comboIndex=None):
self.deleteComboDelegates()
comboText=self.combo.currentText()
self.tableModel.setFilter(comboText=comboText)
self.addComboDelegates()
self.tableModel.layoutChanged.emit()
def searchLineEditied(self, searchText=None):
self.tableModel.setFilter(searchText=searchText)
def viewClicked(self, indexClicked):
item=self.tableModel.data(indexClicked, QtCore.Qt.UserRole)
print 'ID: %s, name: %s, category: %s'%(item.ID,item.name,item.category)
def deleteComboDelegates(self):
for row in range(self.tableModel.rowCount()):
index=self.tableModel.index(row, 3, QtCore.QModelIndex())
self.tableView.closePersistentEditor(index)
def addComboDelegates(self):
for row in range(self.tableModel.rowCount()):
index=self.tableModel.index(row, 3, QtCore.QModelIndex())
self.tableView.openPersistentEditor(index)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
There are three QTableViews: A, B, C. All three share the same SourceModel.
There are three column names: "Items A", "Items B" and "Items C" stored in self.columnNames list.
Each QTableView was assigned an instance of the same ProxyModel with proxy's objectName set to "proxyA", "proxyB" and "proxyC".
I want the left-side QTableView to list only the items "A" using a single column with its header named "Items A".
The middle tableViewB should only list "Items_B" with the column-header called "Items B".
And the third tableView should list only items "C" with the column name set to "Items C".
The source code is below. I really wanna know how to do it.
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys, os
class Model(QAbstractTableModel):
def __init__(self, parent=None, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.items =[
['Item_A_0','Item_A_12','Item_C_330'],
['Item_C_20','Item_B_11','Item_B_12'],
['Item_C_101','Item_A_24','Item_B_77']
]
self.columnNames=['Items A', 'Items B', 'Items C']
def headerData(self, col, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.columnNames[col]
def flags(self, index):
return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
def rowCount(self, parent):
return len(self.items)
def columnCount(self, parent):
return len(self.columnNames)
def data(self, index, role):
if not index.isValid(): return QVariant()
row=index.row()
column=index.column()
if row>len(self.items): return QVariant()
if column>len(self.items[row]): return QVariant()
columnName=self.headerData(column, Qt.Horizontal, Qt.DisplayRole)
if role == Qt.EditRole or role == Qt.DisplayRole:
return QVariant(self.items[row][column])
return QVariant()
def setData(self, index, value, role=Qt.EditRole):
if index.isValid():
if role == Qt.EditRole:
row = index.row()
column=index.column()
if row>len(self.items) or column>len(self.items[row]):
return False
else:
self.items[row][column]=value
return True
return False
class Proxy(QSortFilterProxyModel):
def __init__(self):
super(Proxy, self).__init__()
def filterAcceptsRow(self, row, parent):
sourceModel=self.sourceModel()
columns=sourceModel.columnCount(QModelIndex())
return True
class MyWindow(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
tablemodel=Model(self)
proxyA=Proxy()
proxyA.setObjectName('proxyA')
proxyA.setSourceModel(tablemodel)
tableviewA=QTableView(self)
tableviewA.setModel(proxyA)
proxyB=Proxy()
proxyB.setObjectName('proxyB')
proxyB.setSourceModel(tablemodel)
tableviewB=QTableView(self)
tableviewB.setModel(proxyB)
proxyC=Proxy()
proxyC.setObjectName('proxyC')
proxyC.setSourceModel(tablemodel)
tableviewC=QTableView(self)
tableviewC.setModel(proxyC)
layout=QHBoxLayout(self)
layout.addWidget(tableviewA)
layout.addWidget(tableviewB)
layout.addWidget(tableviewC)
self.setLayout(layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
With QTableView set as editable using QAbstractTableModel's flag() method:
def flags(self, index):
return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
double-clicking the QTableView's item puts this item into the editing mode. By default the pre-existing string disappears from the field and an entire item is blank. I wonder if this behavior can be avoided or overridden?
Here is the QTableView field before the user double-clicks it:
And here is how it looks on double-click:
EDITED WORKING CODE (Many thanks to M4rtini):
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys, os
class Model(QAbstractTableModel):
def __init__(self, parent=None, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.items =[
['Row0_Column0','Row0_Column1','Row0_Column2'],
['Row1_Column0','Row1_Column1','Row1_Column2'],
['Row2_Column0','Row2_Column1','Row2_Column2']
]
def flags(self, index):
return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
def rowCount(self, parent):
return len(self.items)
def columnCount(self, parent):
return 3
def data(self, index, role):
if not index.isValid(): return QVariant()
row=index.row()
column=index.column()
if row>len(self.items): return QVariant()
if column>len(self.items[row]): return QVariant()
if role == Qt.EditRole or role == Qt.DisplayRole:
return QVariant(self.items[row][column])
return QVariant()
def setData(self, index, value, role=Qt.EditRole):
if index.isValid():
if role == Qt.EditRole:
row = index.row()
column=index.column()
if row>len(self.items) or column>len(self.items[row]):
return False
else:
self.items[row][column]=value
return True
return False
class MyWindow(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
tablemodel=Model(self)
tableview=QTableView(self)
tableview.setModel(tablemodel)
layout=QVBoxLayout(self)
layout.addWidget(tableview)
self.setLayout(layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
You need to sett the return value for data when called with EditRole:
def data(self, index, role):
if not index.isValid(): return false
row=index.row()
if row>len(self.items): return false
if role == Qt.DisplayRole or role == Qt.EditRole:
return self.items[row]