Search code examples
pythonpyqtpyqt5qsqltablemodel

CheckBox in QListView using QSqlTableModel


I am learning the PyQt5 framework and attempting to build a QListView of items with a checkbox in front of each item. Most of the examples I have read don't show how to accomplish this with the QSqlTableModel. Can someone please point me in the right direction?

db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName("./Data/mydbase.db")
db.open()
model = QSqlTableModel()
model.setTable("labdata")
model.setSort(1,0)
model.select()
while model.canFetchMore():
    model.fetchMore()
self.ui.lst_LabData.setModel(model)
self.ui.lst_LabData.setModelColumn(1)
self.ui.lst_LabData.show()

Solution

  • A possible option is to enable the flag Qt::ItemIsUserCheckable, and overwrite the data() and setData() methods when the role is Qt::CheckStateRole, to store the data we create a dictionary.

    class TableModel(QSqlTableModel):
        def __init__(self, *args, **kwargs):
            QSqlTableModel.__init__(self, *args, **kwargs)
            self.checkeable_data = {}
    
        def flags(self, index):
            fl = QSqlTableModel.flags(self, index)
            if index.column() == 1:
                fl |= Qt.ItemIsUserCheckable
            return fl
    
        def data(self, index, role=Qt.DisplayRole):
            if role == Qt.CheckStateRole and (
                self.flags(index) & Qt.ItemIsUserCheckable != Qt.NoItemFlags
            ):
                if index.row() not in self.checkeable_data.keys():
                    self.setData(index, Qt.Unchecked, Qt.CheckStateRole)
                return self.checkeable_data[index.row()]
            else:
                return QSqlTableModel.data(self, index, role)
    
        def setData(self, index, value, role=Qt.EditRole):
            if role == Qt.CheckStateRole and (
                self.flags(index) & Qt.ItemIsUserCheckable != Qt.NoItemFlags
            ):
                self.checkeable_data[index.row()] = value
                self.dataChanged.emit(index, index, (role,))
                return True
            return QSqlTableModel.setData(self, index, value, role)
    

    Example:

    def createConnection():
        db = QSqlDatabase.addDatabase("QSQLITE");
        db.setDatabaseName(":memory:");
        if not db.open():
            print("Cannot open database"),
            print("Unable to establish a database connection.\n"
                            "This example needs SQLite support. Please read "
                            "the Qt SQL driver documentation for information how "
                            "to build it.\n\n"
                            "Click Cancel to exit.")
            return False
    
        query = QSqlQuery()
        query.exec_("create table person (id INTEGER PRIMARY KEY AUTOINCREMENT, "
                   "firstname VARCHAR(20), lastname VARCHAR(20))");
        query.exec_("insert into person(firstname, lastname) values('Danny', 'Young')");
        query.exec_("insert into person(firstname, lastname) values('Christine', 'Holand')");
        query.exec_("insert into person(firstname, lastname) values('Lars', 'Gordon')");
        query.exec_("insert into person(firstname, lastname) values('Roberto', 'Robitaille')");
        query.exec_("insert into person(firstname, lastname) values('Maria', 'Papadopoulos')");
    
        return True
    
    class Widget(QMainWindow):
        def __init__(self):
            QMainWindow.__init__(self)
            lv = QListView(self)
            self.setCentralWidget(lv)
            model = TableModel(self)
            model.setTable("person")
            model.select()
            lv.setModel(model)
            lv.setModelColumn(1)
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        if not createConnection():
            sys.exit(-1)
        ex = Widget()
        ex.show()
        sys.exit(app.exec_())
    

    enter image description here