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_())
    
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.