1

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.

Philip Whitten
  • 293
  • 2
  • 16
  • If you place the load of an image in the paint() method the application will become slow since that method is called every time doing the reading of the image at every moment consuming resources, so what is your model? Could you provide a [mcve] ?, depending on the model you show you could indicate how to load the icon to the model. Do you want the icon to be centered in the box? – eyllanesc Sep 27 '18 at 22:02
  • I have edited my question to describe the model being used. I would like the icon to be centred in the box, and, if possible to adjust in size if the box changes in size. – Philip Whitten Sep 27 '18 at 22:16
  • Do you want it to occupy the entire rectangle or just have the same height? – eyllanesc Sep 27 '18 at 22:29
  • Just the same height – Philip Whitten Sep 27 '18 at 22:30
  • from what I understand, the icons depend on the characteristic of another column – eyllanesc Sep 27 '18 at 22:31
  • So they are like icons of A, B, C, if the row meets a characteristic then you want the icon A, if it meets another B and if it is another C, am I correct? – eyllanesc Sep 27 '18 at 22:32
  • Is the icon's path the value of the string, or is there only a number of fixed icons? – eyllanesc Sep 27 '18 at 22:37
  • Correct, there are only a fixed number of icons like A, B, and C with the a specific icon being displayed when a row meets a characteristic. At present, the icon's path is not the value of the string - although that is easy for me to implement if that makes the script simpler :) – Philip Whitten Sep 27 '18 at 22:43
  • okay, I only have one last question, does the column where you want the icon exist in the model ?, that is, what you want is to delete the text of a column and replace it or you want another column to be created. – eyllanesc Sep 27 '18 at 22:45
  • The column already exists and I would like to replace it. However, I am also happy to work with a solution that creates a new column as I can hide the current column. – Philip Whitten Sep 27 '18 at 22:48
  • some feedback?? – eyllanesc Sep 28 '18 at 23:38
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/180974/discussion-between-philip-whitten-and-eyllanesc). – Philip Whitten Sep 29 '18 at 02:39
  • First of all I recommend using the fullpath of the image, just to try. If it works for you then the problem will be the path. If the problem is the path, tell me the fullpath of the image and what it returns: `print(QtCore.QDir.currentPath())` – eyllanesc Sep 29 '18 at 04:30
  • If you do not point out your errors I can not help you, I see that you are using qgis, and many times the relative routes are relative to the main application, not the plugin. – eyllanesc Sep 29 '18 at 04:36
  • I have asked a new question for setting the path for the icon in QGIS here: https://stackoverflow.com/questions/52565084/access-icons-from-within-qgis-plugin – Philip Whitten Sep 29 '18 at 05:27
  • The path of a file belonging to a .qrc is not real but virtual, so if you want to verify that it exists you should use `print(QtCore.QFileInfo(":/plugins/geomAttribute/line_1x.png").exists())` – eyllanesc Sep 29 '18 at 05:41
  • Also to use .qrc in python you must compile it using pyrcc, for example if your .qrc is called some_file.qrc you must execute `pyrcc5 some_file.qrc -o some_file_rc.py` and then import it as `import some_file_rc` – eyllanesc Sep 29 '18 at 05:45

1 Answers1

6

In this answer I will show several methods, and you can choose according to the complexity of the problem.

1. The number of icons are fixed and one column will be reused.

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)

enter image description here

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.

  1. Launch exceptions, this consumes many resources that Qt considers unnecessary so you will never use it.

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.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241