How to make QAbstractTableModel 's data checkable
-
I want to make each cell in the following code can be checked or unchecked by the user ,how to modify the code ?
@import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class MyModel(QAbstractTableModel):
def __init__(self, parent=None): super(MyModel, self).__init__(parent) def rowCount(self, parent = QModelIndex()): return 2 def columnCount(self,parent = QModelIndex()) : return 3 def data(self,index, role = Qt.DisplayRole) : if (role == Qt.DisplayRole): return "Row{}, Column{}".format(index.row() + 1, index.column() +1) return None
if name == 'main':
app =QApplication(sys.argv) tableView=QTableView() myModel = MyModel (None); tableView.setModel( myModel ); tableView.show(); sys.exit(app.exec_())@
-
To be checkable, a model must return the necessary flag from the flags() method, provide legal data from the data() method with the CheckStateRole and also implement the setData() method to allow for the check state to change. See the following full example:
import sip sip.setapi('QString',2) sip.setapi('QVariant',2) from PyQt4.QtGui import * from PyQt4.QtCore import * class MyModel(QAbstractTableModel): def __init__(self, parent=None): QAbstractTableModel.__init__(self, parent) self._checked=[[False for i in xrange(self.columnCount())] for j in xrange(self.rowCount())] def rowCount(self, parent = QModelIndex()): return 2 def columnCount(self,parent = QModelIndex()): return 3 def data(self,index, role = Qt.DisplayRole): if not index.isValid(): return if (role == Qt.DisplayRole): return "Row{}, Column{}".format(index.row()+1, index.column()+1) elif role==Qt.CheckStateRole: return self._checked[index.row()][index.column()] return None def flags(self, index): if not index.isValid(): return return Qt.ItemIsSelectable|Qt.ItemIsEditable|Qt.ItemIsEnabled|Qt.ItemIsUserCheckable def setData(self, index, value, role): if not index.isValid() or role!=Qt.CheckStateRole: return False self._checked[index.row()][index.column()]=value self.dataChanged.emit(index, index) return True if __name__ == '__main__': from sys import argv, exit class Widget(QWidget): def __init__(self, parent=None, **kwargs): QWidget.__init__(self, parent, **kwargs) l=QVBoxLayout(self) self._model=MyModel(self) self._table=QTableView(self) self._table.setModel(self._model) l.addWidget(self._table) app=QApplication(argv) w=Widget() w.show() w.raise_() exit(app.exec_())
Hope this helps ;o)
-
is it necessary to check if the index is valid ?
I post a thread about this question here ,can you have a look ?
http://qt-project.org/forums/viewthread/26955/ -
I am in the habit of always checking the validity of the index when working with models of any shape (list, table, tree) or dimension. With tree models it's more important, but even with lists and tables, for what it realistically costs (which is very little), a bit of defensive programming to prevent unseemly UI errors, crashes or even segmentation faults (this can happen!) is worth it. I regularly work with models that are 100's and 1000's of columns wide and 1,000,000's of rows long and it doesn't have an adverse effect.
WRT to this:
@
if (!index.isValid())
return QVariant();if (index.row() >= stringList.size()) return QVariant();
@
The second check is entirely contextual: if/how you do this is based on the likelihood of bad/non-existant accesses and the underlying data structures ability to handle these.
So I suppose the long and the short of it is: check the validity of the index as there's no reason not to, check the validity of the data access as/if/when appropriate to your design.
Hope this answers your question ;o)
-
a minimized example
import sys from PySide2.QtWidgets import * from PySide2.QtCore import * from PySide2.QtGui import * from PySide2.QtSql import * class MyModel(QSqlTableModel): def __init__(self, parent=None): super().__init__(parent) self._checked = [[False for i in range(self.columnCount())] for j in range(self.rowCount())] def rowCount(self, parent=QModelIndex()): return 2 def columnCount(self, parent=QModelIndex()): return 3 def data(self, index, role): if (role == Qt.DisplayRole): return "Row{}, Column{}".format(index.row() + 1, index.column() + 1) elif role == Qt.CheckStateRole: print('data(self, index, role)-------------', index.data()) return self._checked[index.row()][index.column()] # show CheckBox's check state return None # be sure to return super().data(index, role) if worked with QSqlTableModel; def flags(self, index): return super().flags(index) | Qt.ItemIsUserCheckable def setData(self, index, value, role): # implement the setData() method to allow for the check state to change if role == Qt.CheckStateRole: print(value) self._checked[index.row()][index.column()] = value # CheckBox's check state depends on the value return True # Returns true if the value could be set return False # be sure to return super().setData(index, value, role) if worked with QSqlTableModel;Returns true if value is equal to the current value. However, the value will not be submitted to the database.; if __name__ == '__main__': app = QApplication(sys.argv) tableView = QTableView() myModel = MyModel(None) tableView.setModel(myModel) tableView.show() sys.exit(app.exec_())
-
@redstoneleo Thanks, it's incredible how hard it is to find a straightforward example of this functionality.