With PyQt5 I am trying to use QItemDelegate to show an icon instead of a text string in a cell in a table. Essentially I construct a subclass of the QItemDelegate using:
de = MyDelegate(self.attribute_table_view)
Here dself.attribute_table_view
is a `QTableView' object.
I try to draw an icon in every cell in a specific column using:
class MyDelegate(QItemDelegate):
def __init__(self, parent=None, *args):
QItemDelegate.__init__(self, parent, *args)
def paint(self, painter, option, index):
painter.save()
value = index.data(Qt.DisplayRole)
line_1x = QPixmap('line_1x.png')
painter.setBrush(Qt.gray)
painter.setPen(Qt.black)
painter.drawPixmap(QRectF(0, 0, 48, 24), line_1x, QRectF(0, 0, 48, 24))
painter.restore()
With the painter.drawPixmap()
how do I tell it to draw in each cell in the table like one achieves using painter.drawText(option.rect, Qt.AlignVCenter, value)
?
Also, I have noticed that my current script does not report any errors if I enter a filename that doesn't exist for the .png file. Should an error by reported if the .png file does not exist?
My current model is a QgsAttributeTableModel and I want to render the current string value for all cells in one column with icon's where the icon used depends on the string value.
In this answer I will show several methods, and you can choose according to the complexity of the problem.
The logic is to load the icons once, and pass it as an attribute to the delegate, then depending on your logic you get the icon of the list for it modifies get_icon()
method. and we paint the icon through the paint()
method of QIcon.
class MyDelegate(QtWidgets.QStyledItemDelegate):
def __init__(self, icons, parent=None):
super(MyDelegate, self).__init__(parent)
self._icons = icons
def get_icon(self, index):
# get the icon according to the condition:
# In this case, for example,
# the icon will be repeated periodically
icon = self._icons[ index.row() % len(self._icons) ]
return icon
def paint(self, painter, option, index):
icon = self.get_icon(index)
icon.paint(painter, option.rect, QtCore.Qt.AlignCenter)
How to reuse a column you must use the setItemDelegateForColumn()
method to set the delegate to a column
self.attribute_table_view = QtWidgets.QTableView()
self.attribute_table_view.setModel(your_model)
column_icon = 1
icons = [QtGui.QIcon(QtCore.QDir.current().absoluteFilePath(name)) for name in ["clear.png", "heart.png","marker.png", "pen.png"]]
delegate = MyDelegate(icons, self.attribute_table_view)
self.attribute_table_view.setItemDelegateForColumn(column_icon, delegate)
I have noticed that my current script does not report any errors if I enter a filename that doesn't exist for the .png file. Should an error by reported if the .png file does not exist?
Qt will not notify if the file does not exist, you have to verify, for example with the isNull()
function. There are 2 ways to notify:
1. The first one is to return a boolean indicating if the data is loaded or not, but when using a constructor it only returns the constructed object and throws.
Another way that especially Qt notifies that there is an error is through signals but these are only for QObject and QIcon, QPixmap, QImage are not QObjects.
So in conclusion the responsibility to verify or not falls on the developer.