I am using PyQt5 to make an application. One of my widgets will be a QListView that displays a list of required items, e.g. required to cook a particular dish, say.
For most of these, the listed item is the only possibility. But for a few items, there is more than one option that will fulfill the requirements. For those with multiple possibilities, I want to display those possibilities in a functional QComboBox. So if the user has no whole milk, they can click that item, and see that 2% milk also works.
How can I include working combo boxes among the elements of my QListView?
Below is an example that shows what I have so far. It can work in Spyder or using python -i, you just have to comment or uncomment as noted. By "work", I mean it shows the required items in QListView, but the combo boxes show only the first option, and their displays can't be changed with the mouse. However, I can say e.g. qb1.setCurrentIndex(1) at the python prompt, and then when I move the mouse pointer onto the widget, the display updates to "2% milk". I have found it helpful to be able to interact with and inspect the widget in Spyder or a python interpreter, but I still have this question. I know there are C++ examples of things like this around, but I have been unable to understand them well enough to do what I want. If we can post a working Python example of this, it will help me and others too I'm sure.
from PyQt5.QtWidgets import QApplication, QComboBox, QListView, QStyledItemDelegate
from PyQt5.QtCore import QAbstractListModel, Qt
# A delegate for the combo boxes.
class QBDelegate(QStyledItemDelegate):
def paint(self, painter, option, index):
painter.drawText(option.rect, Qt.AlignLeft, self.parent().currentText())
# my own wrapper for the abstract list class
class PlainList(QAbstractListModel):
def __init__(self, elements):
super().__init__()
self.elements = elements
def data(self, index, role):
if role == Qt.DisplayRole:
text = self.elements[index.row()]
return text
def rowCount(self, index):
try:
return len(self.elements)
except TypeError:
return self.elements.rowCount(index)
app = QApplication([]) # in Spyder, this seems unnecessary, but harmless.
qb0 = 'powdered sugar' # no other choice
qb1 = QComboBox()
qb1.setModel(PlainList(['whole milk','2% milk','half-and-half']))
d1 = QBDelegate(qb1)
qb1.setItemDelegate(d1)
qb2 = QComboBox()
qb2.setModel(PlainList(['butter', 'lard']))
d2 = QBDelegate(qb2)
qb2.setItemDelegate(d2)
qb3 = 'cayenne pepper' # there is no substitute
QV = QListView()
qlist = PlainList([qb0, qb1, qb2, qb3])
QV.setModel(qlist)
QV.setItemDelegateForRow(1, d1)
QV.setItemDelegateForRow(2, d2)
QV.show()
app.exec_() # Comment this line out, to run in Spyder. Then you can inspect QV etc in the iPython console. Handy!