The short answer is it turns out to be that I was not getting arraydata to be a list of lists.
(If I understand correctly, the list should look like: [[col1, col2, col3],[col1, col2, col3],...]
so each list is the columns of the row.)

As I often do when I'm confused, I make a minimum version of the code and figure out how to get that working.
This often helps enlighten me...
I did and it is shown below.

I was not able to grok a few things but this does work.

The docs for rowCount() and columnCount() say they should return 0 if it is a table. (it's not clear to me from the
docs whether, for a table it should ever return the actual count of rows/columns...) It shows the parent argument
to be a QModelIndex. What I gleaned is that a parent for trees would have children, where a table cell does not.
And, my experiments have always resulted in a non-valid parent when the selected cell of the table is sent as this argument.

I was also never able to get insertRow() to insert a row.
(Hence this example modifies the arraydata, then emits layoutChanged. Is this a valid or proper approach?)
The docs indicate that insertRow() calls insertRows() which is virtual. But it is not clear to me from the docs whether
my implementation of insertRows() MUST do all the actual inserting (is insertRow/s actually inserting a row in the
model's modelindex and not the model data?)

The docs also say:
"If row is 0, the rows are prepended to any existing rows in the parent.

If row is rowCount(), the rows are appended to any existing rows in the parent."

So, but what if the current model data is empty? i.e. arraydata = []
And, this appears to imply that rowCount() could return the actual number of rows...not 0 as noted above.

It also says: "If parent has no children, a single column with count rows is inserted."
But the parent ( a QModelIndex) for a table never has children.

And what does the view actually do when beginInsertRows/endInsertRows are called? Does this allow the view to manage if the
view needs to scroll or resize? Wouldn't this happen when layoutChanged is emitted anyway?

Sorry for the long post.

Qt Code:
  1. import sys
  2.  
  3. from PyQt5 import Qt, QtCore, QtGui, QtWidgets
  4. from PyQt5.QtCore import *
  5. from PyQt5.QtWidgets import *
  6.  
  7. import TableUpdate_ui
  8.  
  9. class TblUpd(QtWidgets.QDialog, TableUpdate_ui.Ui_Dialog):
  10. def __init__(self, parent=None):
  11. QDialog.__init__(self, parent)
  12. self.setupUi(self)
  13. self.pushButton_update.clicked.connect(self.on_update_btn_click)
  14. self.pushButton_add.clicked.connect(self.on_add_btn_click)
  15. self.pushButton_insert.clicked.connect(self.on_insert_btn_click)
  16. self.tabledata = []
  17. # set the table model
  18. self.tablemodel = MyTableModel(self.tabledata, ['Controls'], self)
  19. self.tableView.horizontalHeader().setVisible(True)
  20. self.tableView.setModel(self.tablemodel)
  21. self.tableView.resizeColumnsToContents()
  22. self.tableView.selectRow(0)
  23.  
  24. def on_update_btn_click(self):
  25. print('Update button clicked.')
  26. print('lineEdit.text = {0}'.format(self.lineEdit.text()))
  27. if self.lineEdit.text() == '':
  28. value = 'blank'
  29. else:
  30. value = self.lineEdit.text()
  31. print('value = {0}'.format(value))
  32. selectedindex = self.tableView.currentIndex()
  33. print(self.tablemodel.setData(selectedindex, value,
  34. QtCore.Qt.EditRole))
  35. self.tableView.resizeColumnsToContents()
  36. pass
  37.  
  38. def on_add_btn_click(self):
  39. print('Insert button clicked.')
  40. print('lineEdit.text = {0}'.format(self.lineEdit.text()))
  41. if self.lineEdit.text() == '':
  42. value = 'blank'
  43. else:
  44. value = self.lineEdit.text()
  45. print('value = {0}'.format(value))
  46. self.tablemodel.arraydata.extend([[value]])
  47. self.tablemodel.layoutChanged.emit()
  48. self.tableView.resizeColumnsToContents()
  49.  
  50. def on_insert_btn_click(self):
  51. print('Insert clicked.')
  52. if self.lineEdit.text() == '':
  53. value = 'blank'
  54. else:
  55. value = self.lineEdit.text()
  56. print('value = {0}'.format(value))
  57. selectedindex = self.tableView.currentIndex()
  58. self.tablemodel.arraydata.insert(selectedindex.row(), [value])
  59. self.tablemodel.layoutChanged.emit()
  60. self.tableView.resizeColumnsToContents()
  61. pass
  62.  
  63. class MyTableModel(QtCore.QAbstractTableModel):
  64. def __init__(self, datain, headerdata, parent=None):
  65. """
  66. Args:
  67. datain: a list of lists\n
  68. headerdata: a list of strings
  69. """
  70. QtCore.QAbstractTableModel.__init__(self, parent)
  71. self.arraydata = datain
  72. self.headerdata = headerdata
  73.  
  74. def rowCount(self, parent):
  75. if parent.isValid():
  76. return 0
  77. return len(self.arraydata)
  78.  
  79. def columnCount(self, parent):
  80. if parent.isValid():
  81. return 0
  82. else:
  83. return 1
  84.  
  85. def data(self, index, role):
  86. print('In data()')
  87. if not index.isValid():
  88. print('Invalid index in MyModel>data')
  89. retval = QtCore.QVariant()
  90. elif role != QtCore.Qt.DisplayRole:
  91. retval = QtCore.QVariant()
  92. else:
  93. retval = QtCore.QVariant(self.arraydata[index.row()][index.column()])
  94. print(self.arraydata[index.row()][index.column()])
  95. print(retval)
  96. return retval
  97.  
  98. def setData(self, index, value, role):
  99. if role == QtCore.Qt.EditRole and index.isValid():
  100. print(index.row())
  101. self.arraydata[index.row()] = [value]
  102. print('Return from rowCount: {0}'.format(self.rowCount(index)))
  103. self.dataChanged.emit(index, index, [QtCore.Qt.DisplayRole])
  104. return True
  105. return False
  106.  
  107. def headerData(self, col, orientation, role):
  108. if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
  109. return QtCore.QVariant(self.headerdata[col])
  110. return QtCore.QVariant()
  111.  
  112. def main():
  113. app = QtWidgets.QApplication(sys.argv)
  114. tblupd = TblUpd()
  115. tblupd.show()
  116. sys.exit(app.exec_())
  117.  
  118. if __name__ == '__main__':
  119. main()
To copy to clipboard, switch view to plain text mode