selectRow after insertRow not working

I am new to PyQt and having to really dig to understand how the objects fit together. I am probably overlooking some basic things at this point. I have started building my application, but keep tripping into things that don’t work the way I want. Please be understanding if I am missing basic concepts. Doing this as retirement project, no longer being paid to code.
The problem is that I want to add a row to a tableView and have it selected. This code is extracted from a more complex environment.
What am I doing wrong?

import sys
from PyQt5 import QtCore as qtc
from PyQt5 import QtWidgets as qtw

"""
	Model: based on QAbstractTableModel
	View: QTable view
	data: simple table of integers (3 columns)
	
	Implemented insert and remove row methods.
		I want an inserted table row to be selected

	Problem: selectRow after insert of table row works only
		if I have just deleted the next to last entry in the table
"""

# Model +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
class TableModel(qtc.QAbstractTableModel):

	def __init__(self, data):
		super(TableModel, self).__init__()
		self._data = data

	def data(self, index, role):
		if role == qtc.Qt.DisplayRole:
			value = self._data[index.row()][index.column()]
			return str(value)
			
	def setData(self, index, value, role):
		if role == qtc.Qt.EditRole:
			self._data[index.row()][index.column()] = value
			return True

	def rowCount(self, index):
		rows = len(self._data)
		return rows

	def columnCount(self, index):
		cols = len(self._data[0])
		return cols
	
	def flags(self, index):
		flags = qtc.Qt.ItemIsSelectable|qtc.Qt.ItemIsEnabled|qtc.Qt.ItemIsEditable
		return flags

	def removeRow(self, row):
		self.rowsAboutToBeRemoved.emit(qtc.QModelIndex(), row, row)
		self._data.pop(row)
		self.rowsRemoved.emit(qtc.QModelIndex(), row, row)

	def insertRow(self, data)->int:
		row = len(self._data) + 1
		self.rowsAboutToBeInserted.emit(qtc.QModelIndex(), row, row)
		self._data.append(data)
		self.rowsInserted.emit(qtc.QModelIndex(), row, row)
		return row

# end class TableModel

class MainWindow(qtw.QMainWindow):

	def __init__(self):
		super().__init__()
		self.setMinimumSize(qtc.QSize(350, 200))
		self.cIndex = None		# current selection
		self.pIndex = None		# previous selection
		self.rowData = 10		# for generated adds
		self.sm = None			# selection model

		# view +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		self.table = qtw.QTableView()
		self.table.setSelectionMode(qtw.QAbstractItemView.SingleSelection)
		self.table.setSelectionBehavior(qtw.QAbstractItemView.SelectRows)

		# model +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		data = [ [1, 9, 2] ] 	# start with 1 row
		self.model = TableModel(data)
		self.table.setModel(self.model)
		sm = self.table.selectionModel()
		sm.currentRowChanged.connect(self.currentRowChanged)
		self.sm = sm

		# buttons ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		buttons = qtw.QHBoxLayout()
		self.pbAdd = qtw.QPushButton('Add')
		self.pbDelete = qtw.QPushButton('Delete')
		self.pbAdd.clicked.connect(self.pbAddClicked)
		self.pbDelete.clicked.connect(self.pbDeleteClicked)

		# layout ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		vBox = qtw.QVBoxLayout()
		vBox.addWidget(self.table)
		buttons.addWidget(self.pbAdd)
		buttons.addWidget(self.pbDelete)
		vBox.addLayout(buttons)
		# complete main window
		self.widget = qtw.QWidget()
		self.widget.setLayout(vBox)
		self.setCentralWidget(self.widget)
		self.show()

	def currentRowChanged(self, cIndex, pIndex):
		self.cIndex = cIndex
		self.pIndex = pIndex

	# add row
	def pbAddClicked(self):
		col = self.rowData
		data = [col, col+1, col+2]
		self.rowData += 10
		row = self.model.insertRow(data)
		# select the inserted row
		# *** this only works when the next to last entry has been deleted ???
		self.table.selectRow(row)
		
	# remove row
	def pbDeleteClicked(self):
		row = self.cIndex.row()
		self.model.removeRow(row)

# end class MainWindow

app=qtw.QApplication([])
window=MainWindow()
app.exec_()

I found my own very basic problem. It wasn’t related to the interaction between the view, selection model and model. Which thanks to my problem and hours spent looking at the documentation and drawing diagrams I now understand much better. I was using an invalid index for my selectRow call. I would expect an error, but apparently the call is just ignored. No additional responses are needed.

1 Like

Thanks for the update @allenwjohnson11084 glad you got it sorted!

When you say invalid index, was the index out of bounds or was index.isValid() returning False? There are quite a few methods that will return an “invalid index” if something isn’t there, but it’s not considered an error – e.g. the parent of a top-level item in a tree will return an invalid parent index. In a lot of cases you can consider it the model equivalent of Python’s None – a valid empty value.

Not sure if it’s relevant to the issue but when overriding methods on your subclass you should follow the same signature as the superclass, e.g. insertRow should accept both the data and the location to insert it, and return a bool for success/failure, rather than the index.

insertRow(int row, const QModelIndex &parent = QModelIndex())

Since selections are handled by the view, and inserts on the model, to do what you’re trying to achieve (auto select inserted rows) I’d probably use the model .rowsInserted and hook that into the selection model for the table view.

P.S. Apologies for the delay in replying I’m out of office (house being renovated) so checking in less frequently for the next 2 weeks.