I have created a model class of type QAbstractTableModel to which I have added a number of methods as shown here:
class resultsModel(QAbstractTableModel):
def __init__(self, parent, headerData, arraydata, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.arraydata = arraydata
self.headerdata = headerData #['Timestamp', 'Force (N)', 'Diplacement (mm)']
def rowCount(self, parent):
return len(self.arraydata)
def columnCount(self, parent):
if len(self.arraydata) > 0:
return len(self.arraydata[0])
return 0
def headerData(self, col, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.headerdata[col]
return None
#Make table cells non-editable
def flags(self, index):
return Qt.ItemIsEnabled | Qt.ItemIsSelectable
def data(self, index, role):
if not index.isValid():
return None
value = self.arraydata[index.row()][index.column()]
if role == Qt.EditRole:
return value
elif role == Qt.DisplayRole:
return value
def setData(self, index, value, role):
if not index.isValid():
return None
row = index.row()
column = index.column()
self.arraydata[row][column] = value
self.dataChanged.emit(index, index)
return True
def setHeaderData(self, col, orientation, value, role):
if role != Qt.DisplayRole or orientation != Qt.Horizontal:
return False
self.headerdata[col] = value
result = self.headerdata[col]
if result:
self.headerDataChanged.emit(orientation, col, col)
return result
When the application starts I use a QTableview with the model above behind it:
resultsHeaders = ['Timestamp', 'Force (N)', 'Diplacement (mm)']
resultsData = [['','','']]
self.resultsTableModel = resultsModel(self, resultsHeaders, resultsData)
self.resultsTable = QTableView()
self.resultsTable.setModel(self.resultsTableModel)
During runtime, if a serial device is connected, I want to add some additional columns to the model but I am having difficulty implementing an 'insertColumns' method for the model before I add the new header values.
#insert columns
???
#update header values
for i in range(len(resultsHeaders)):
self.resultsTable.model().setHeaderData(i, Qt.Horizontal, str(resultsHeaders[int(i)]), Qt.DisplayRole)
An appropriate "insert column(s)" function must be implemented, as the model should correctly be updated to reflect the actual column count, so that the new headers are also correctly shown.
In order to correctly add columns, both beginInsertColumn()
(before adding new column data) and endInsertColumn()
(at the end of the operation) should be properly called.
Normally, adding more columns would require to implement insertColumns()
, but considering the situation and the fact that they would call both methods anyway, there's no need to do that, and a custom function will be fine.
The following only inserts a single column, if you want to add more columns at once, just ensure that the third argument of beginInsertColumns
correctly reflects that (newColumn + len(columnsToAdd)
) and that the header data and new empty values for the array correspond to the new column count.
class ResultsModel(QAbstractTableModel):
# ...
def addColumn(self, name):
newColumn = self.columnCount()
self.beginInsertColumns(QModelIndex(), newColumn, newColumn)
self.headerdata.append(name)
for row in self.arraydata:
row.append('')
self.endInsertColumns()
# ...
class Whatever(QWidget):
# ...
def addColumn(self):
name = 'New column {}'.format(self.resultsTableModel.columnCount())
self.resultsTableModel.addColumn(name)
Note that:
rowCount()
and columnCount()
should have a default keyword parent
argument as the base implementation does (accepted practice involves parent=QModelIndex()
);