0

I have a QtableView with data from a file. I added 3 columns with checkboxes, but now I need to know what checkbox is clicked (Row, column, data). This is working for the cell itself but when clicking the checkbox it gives the latest data or if no data it's -1 and None.

I tried to remove a lot of code so I hope this is not to much or to less.

self.model = TableModel([headers, newRows])
self.proxy_model.setSourceModel(self.model)
self.tableView.setModel(self.proxy_model)


self.tableView.clicked.connect(self.cellClicked)

def cellClicked(self):
    try:
        index = self.tableView.selectionModel().currentIndex()
        row = index.row()
        col = index.column()
        data = index.data()
        # print(index.sibling(row,col).data())
        if isinstance(data, QtWidgets.QCheckBox):
            print(f'Child: {index.child.row()}')
            data = data.text()
            print(data.isChecked())
        print(f'Row:\t{row}\nColumn:\t{col}\nData:\t{data}\n')
    except Exception as e:
        print(e)

class TableModel(QAbstractTableModel):
    def __init__(self, data):
        super().__init__()
        self.checks = {}

        self.headers = data[0]
        self.rows = data[1]
        
    def data(self, index, role):
        try:
            if role == Qt.ItemDataRole.DisplayRole or role == Qt.ItemDataRole.EditRole:
                return self.rows[index.row()][index.column()]
            elif role == Qt.ItemDataRole.CheckStateRole and (index.column() == 0 or index.column() == 6 or index.column() == 7):
                return self.checkState(QPersistentModelIndex(index))

    def setData(self, index, value, role = Qt.ItemDataRole.EditRole):
        if value is not None and role == Qt.ItemDataRole.EditRole:
            self.rows[index.row()][index.column()] = value
            # self.dataChanged.emit(index, index)
            return True
        elif not index.isValid():
            return False
        elif role == Qt.ItemDataRole.CheckStateRole:
            self.checks[QPersistentModelIndex(index)] = value
            return True
        return False

    def checkState(self, index):
        if index in self.checks.keys():
            return self.checks[index]
        else:
            return Qt.CheckState.Unchecked

    def flags(self, index):
        col = index.column()
        if col == 0 or col == 6 or col == 7:
            return Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsEditable | Qt.ItemFlag.ItemIsUserCheckable
        else:
            return Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEditable
Michael
  • 3
  • 5
  • The check state doesn't automatically reflect a clicked index. A state change can only be properly detected by connecting to `dataChanged()`, but since you're already using a custom model, you could even create a dedicated signal that is emitted whenever `setData` is called with a `CheckStateRole` directly using the QModelIndex as argument. – musicamante Aug 22 '22 at 15:06
  • Thanks for your reply. Do you have an example? I found https://stackoverflow.com/questions/37034190/qtableview-not-updated-on-datachanged but I don't get it. – Michael Aug 23 '22 at 06:44
  • I added a print statement in setData after the elif checkstaterole. That prints the right data. After that I placed self.dataChanged.emit(index, index) But what does this part of code then? – Michael Aug 23 '22 at 07:36
  • I'm not on a computer, so I can't write code reliably, just do some research on creating and using custom signals in Pyqt. Note thay you should emit that signal in `setData()` when setting the `CheckStateRole`, but you should also **always** emit `dataChanged` whenever the data has changed, so uncomment that line in `setData()` and do it also for all cases in which you actually update model data (which normally is when you're going to return `True`). – musicamante Aug 23 '22 at 07:39
  • Sorry if i don't understand but I'm not familiar with QtableView. The checkboxes give me the right row and column but know I need to know the checkstate to change other checkbox (Want a limit of 1 checked checkbox per row) and save it so I can send it to a file/database. – Michael Aug 23 '22 at 13:40
  • That has nothing to do with the table, but with the model. As already said, add a custom signal for the model and emit it in `setData` when the role is `CheckStateRole`. Since the signal is made by you, you can use any argument you need. Then connect that signal to the function you need. I suggest you to carefully read the documentation about [model view programming](https://doc.qt.io/qt-6/model-view-programming.html) to better understand how it works (I know it's written for C++ but the concepts are exactly the same for python, and the syntax is not that different). – musicamante Aug 23 '22 at 15:37

0 Answers0