Insert a widget in model view table cell

I need to add a list of widgets to a table cell. I tried to add QLineEdit in DisplayRloe, does not work:

from PySide2 import QtCore, QtWidgets

class Project:
    def __init__(self, id, project_name):
        self.id = id
        self.name = project_name


class TableModel(QtCore.QAbstractTableModel):
    def __init__(self, data, parent=None):
        QtCore.QAbstractTableModel.__init__(self, parent)
        self._data = data
        self.header = ['ID', 'Name']

    def headerData(self, col, orientation, role):
        if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
            return self.header[col]

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

    def columnCount(self, parent):
        return 2

    def data(self, index, role):

        if not index.isValid():
            return

        row = index.row()
        column = index.column()


        if role == QtCore.Qt.DisplayRole:
            if column == 0:
                return self._data[row].id
            else:
                box = QtWidgets.QLineEdit()
                box.setText('X')

                return [box]

app = QtWidgets.QApplication([])

table = QtWidgets.QTableView()
data = [Project(0, 'Project_A'), Project(1, 'Project_B')]
table_model = TableModel(data)
table.setModel(table_model)

table.show()
app.exec_()

Wouldn’t you use QtCore.Qt.EditRole instead of DisplayRole? (I’m just getting back up to speed with the abstract model stuff after not touching it for like 8 years so my memory is super fuzzy).

Thanks, Bob!
Tried to set up via EditRole in both, setData and data methods, did not work as well…

Generally they way you would use model/view architecture is the model stores all your data and the view would actually display that data. You would not store a widget in the model, you would store your data for that cell in the model, but how that data shows up is up to the view. Reading the help file

The items shown in a table view, like those in the other item views, are rendered and edited using standard delegates. However, for some tasks it is sometimes useful to be able to insert widgets in a table instead. Widgets are set for particular indexes with the setIndexWidget() function, and later retrieved with indexWidget().

So if need a particular widget to show up in a specific cell I would look at the TableView class instead. If you just want to be able to edit the info in the cell have a look at this example

    import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt


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

	
	def data(self, index, role):
		if role == Qt.DisplayRole or role == Qt.EditRole:
			# See below for the nested-list data structure.
			# .row() indexes into the outer list,
			# .column() indexes into the sub-list
			return self._data[index.row()][index.column()]
	
	def setData(self, index, value, role):
		self._data[index.row()][index.column()] = value
		return super(TableModel, self).setData(index, value, role)

	def rowCount(self, index):
		# The length of the outer list.
		return len(self._data)

	def columnCount(self, index):
		# The following takes the first sub-list, and returns
		# the length (only works if all rows are an equal length)
		return len(self._data[0])

	def flags(self, index):  # Qt was imported from PyQt4.QtCore
		if index.column() < 2:
			return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable
		else:
			return Qt.ItemIsEnabled | Qt.ItemIsSelectable

class MyDelegate(QtWidgets.QItemDelegate):
	def __init__(self):
		super().__init__()

	def createEditor(self, parent, option, index):
		if index.column() < 2:
			return super(MyDelegate, self).createEditor(parent, option, index)
		else:
			return None

	def setEditorData(self, editor, index):
		if index.column() < 2:
			# Gets display text if edit data hasn't been set.
			text = (index.data(Qt.EditRole) or index.data(Qt.DisplayRole))
			editor.setText(text)		 
   

class MainWindow(QtWidgets.QMainWindow):
	def __init__(self):
		super().__init__()

		self.table = QtWidgets.QTableView()

		data = [
		  ["4", "9", "2"],
		  ["4", "9", "2"],
		  ["4", "9", "2"],
		  ["4", "9", "2"],
		  ["4", "9", "2"]
		]

		self.model = TableModel(data)
		self.table.setModel(self.model)
		self.delegate = MyDelegate()
		self.table.setItemDelegate(self.delegate)
		self.setCentralWidget(self.table)


app=QtWidgets.QApplication(sys.argv)
window=MainWindow()
window.show()
app.exec_()
1 Like