jeudi 16 février 2023

Eliminate the empty spaces in QAbstractTableModel item when cell is checkable

I am trying to implement a custom QTableView. For that I am subclassing QAbstractTableModel such that it takes a list of strings. Here the implementation.

class ListTableModel(qtc.QAbstractTableModel):
def __init__(self, data: List[List[str]], headers: List[str] = None, edit: List[Union[int, Tuple[int, int]]] = None,
             checks: List[Union[int, Tuple[int, int]]] = None, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self._data = data
    self._headers = headers
    self._edit = edit
    self._checks = checks
    self._check_state = {}

    self.name = None

def get_name(self):
    return self.name

def set_name(self, name: str):
    self.name = name

def check_state(self, value, index):
    if index in self._check_state:
        return self._check_state[index]
    else:
        if value == 0:
            return qtc.Qt.Unchecked
        else:
            return qtc.Qt.Checked

def data(self, index, role):
    if index.isValid() or (0 <= index.row() < self.rowCount() and 0 <= index.column() < self.columnCount()):
        val = self._data[index.row()][index.column()]
        val = fast_real(val, coerce=False)
        if (role == qtc.Qt.DisplayRole or role == qtc.Qt.EditRole) and not index.flags() & qtc.Qt.ItemIsUserCheckable:
            if isinstance(val, float):
                return f"{val:.4f}"
            return str(val)

        if role == qtc.Qt.CheckStateRole and index.flags() & qtc.Qt.ItemIsUserCheckable:
            return self.check_state(val, index)

        return None
    return None

def setData(self, index, value, role):
    if role == qtc.Qt.EditRole:
        val = fast_real(value, coerce=False)
        self._data[index.row()][index.column()] = val
        return True

    if role == qtc.Qt.CheckStateRole:
        self._check_state[index] = value
        return True

    return False

def flags(self, index):
    if self._edit is not None and index.column() in self._edit:
        return qtc.Qt.ItemIsSelectable | qtc.Qt.ItemIsEnabled

    if self._edit is not None and (index.row(), index.column()) in self._edit:
        return qtc.Qt.ItemIsSelectable | qtc.Qt.ItemIsEnabled

    if self._checks is not None and index.column() in self._checks:
        return qtc.Qt.ItemIsSelectable | qtc.Qt.ItemIsEnabled | qtc.Qt.ItemIsUserCheckable

    if self._checks is not None and (index.row(), index.column()) in self._checks:
        return qtc.Qt.ItemIsSelectable | qtc.Qt.ItemIsEnabled | qtc.Qt.ItemIsUserCheckable

    return qtc.Qt.ItemIsSelectable | qtc.Qt.ItemIsEnabled | qtc.Qt.ItemIsEditable

def rowCount(self, parent=None):
    return len(self._data)

def columnCount(self, parent=None):
    return len(self._data[0])

def headerData(self, section, orientation, role):
    if role == qtc.Qt.DisplayRole:
        if orientation == qtc.Qt.Horizontal and self._headers is not None:
            return str(self._headers[section])

The class takes a list of list containing strings (representing the table). A list of strings representing the headers of the columns. The optional arguments edit and checks define which columns (if given as int) or cells (if given as tuple) are editable and checkable. The underlying data structure data takes values of 0 if the corresponding checkbox is unchecked, or any other value if the corresponding checkbox is checked.

My first question is that the cells that are checkable actually show some extra space, apart from drawing the checkbox. A separating line in the middle of the cell is actually visible when selecting the cell. How can I eliminate this? In the data method I control for cells that are checkable, and skip the display of the underlying data if it is. So I do not know how else to proceed here.

EXTRA: I would like to capture the signal that the model emits when any of the checkboxes are checked/unchecked. Any hint on this would be much appreciated as well.




Aucun commentaire:

Enregistrer un commentaire