I'm trying to display some data from a database in a grid view, similar to how a file manager works. I thought of using a QTableView
as the grid view since it did what I wanted out of the box. However, as shown with the below given MRE, even if just a single cell has value, you can still select the other empty cells, how can I prevent this? Basically, I want to make it so that only cells with a value can be selected.
MRE:
from PySide6 import QtWidgets as qtw
from PySide6 import QtGui as qtg
from PySide6 import QtCore as qtc
ROW_COUNT = 5
COL_COUNT = 5
class Model(qtc.QAbstractTableModel):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self._data = [[None for _ in range(COL_COUNT)] for _ in range(ROW_COUNT)]
def data(self, index: qtc.QModelIndex, role: qtc.Qt.ItemDataRole):
if not index.isValid():
return None
if role == qtc.Qt.ItemDataRole.DisplayRole:
return self._data[index.row()][index.column()]
return None
def setData(self, index: qtc.QModelIndex, value, role: qtc.Qt.ItemDataRole=qtc.Qt.ItemDataRole.DisplayRole):
if not index.isValid():
return False
if role == qtc.Qt.ItemDataRole.DisplayRole:
self._data[index.row()][index.column()] = value
return False
def rowCount(self, _):
return ROW_COUNT
def columnCount(self, _):
return COL_COUNT
app = qtw.QApplication()
view = qtw.QTableView()
view.setModel(Model())
view.setShowGrid(False)
view.verticalHeader().setVisible(False)
view.horizontalHeader().setVisible(False)
view.model().setData(view.model().createIndex(0, 0), "this is a test")
view.show()
app.exec()
You need to override the flags()
and ensure that it doesn't return the ItemIsSelectable
flag.
class Model(qtc.QAbstractTableModel):
# ...
def flags(self, index):
flags = super().flags(index)
if index.data() is None:
flags &= ~qtc.Qt.ItemIsSelectable
return flags
In your case, you also probably want to avoid the ItemIsEnabled
, and since these two flags are the default one, you can just return NoItemFlags
def flags(self, index):
if index.data() is None:
return qtc.Qt.NoItemFlags
return super().flags(index)
If you also need to clear the selection, then you could subclass the view and do it in the mousePressEvent()
:
class TableView(qtw.QTableView):
def mousePressEvent(self, event):
index = self.indexAt(event.pos())
if index.isValid() and not index.flags() & qtc.Qt.ItemIsSelectable:
self.clearSelection()
else:
super().mousePressEvent(event)