Set different color to specifc items in QListWidget
<p>I have a <code>QListWidget</code> and I want to add border bottom to each item of the list and set a background color to items and I want to set to specific items a different background color.
So I used <code>my_list.setStyleSheet("QListWidget::item { border-bottom: 1px solid red; background-color: blue;}")</code> and to set background color to specific items I used <code>item.setBackground(QtGui.QColor("#E3E3E3"))</code></p>

<p>The problem is the specif items that I set a different color don't get this color.</p>

<p>You can't use a combination of stylesheets and style settings on a widget â the stylesheet will override any settings on individual items. For example, the following code uses <code>setBackground</code> on each item to change the background colour.</p>

<pre><code>from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

colors = [ '#7fc97f', '#beaed4', '#fdc086', '#ffff99', '#386cb0', '#f0027f', '#bf5b17', '#666666']

class MainWindow(QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        w = QListWidget()
        for n in range(8):
            i = QListWidgetItem('%s' % n)
            i.setBackground( QColor(colors[n]) )
            w.addItem(i)

        self.setCentralWidget(w)

        self.show()


app = QApplication([])
w = MainWindow()
app.exec_()
</code></pre>

<p>The resulting output:</p>

<p><a href="https://i.stack.imgur.com/KaOSU.png" rel="nofollow"><img src="https://i.stack.imgur.com/KaOSU.png" alt="enter image description here"></a></p>

<p>However, if we add the stylesheet line in the result is (and second with only the bottom border):</p>

<p><a href="https://i.stack.imgur.com/iMF70.png" rel="nofollow"><img src="https://i.stack.imgur.com/iMF70.png" alt="enter image description here"></a>
<a href="https://i.stack.imgur.com/3PdUO.png" rel="nofollow"><img src="https://i.stack.imgur.com/3PdUO.png" alt="enter image description here"></a></p>

<p>Unfortunately, there is no way to set the border and the colour for the items. However, what you <em>can</em> do is either insert a custom widget as the list item, or <a href="http://www.saltycrane.com/blog/2008/01/pyqt4-qitemdelegate-example-with/" rel="nofollow">use an item delegate</a> to draw the item. This gives you complete control over appearance, however you have to handle drawing yourself. Below is an example of doing this with a custom delegate:</p>

<pre><code>from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

colors = [ '#7fc97f', '#beaed4', '#fdc086', '#ffff99', '#386cb0', '#f0027f', '#bf5b17', '#666666']


class MyDelegate(QItemDelegate):
    def __init__(self, parent=None, *args):
        QItemDelegate.__init__(self, parent, *args)

    def paint(self, painter, option, index):
        painter.save()

        # set background color
        painter.setPen(QPen(Qt.NoPen))
        if option.state &amp; QStyle.State_Selected:
            # If the item is selected, always draw background red
            painter.setBrush(QBrush(Qt.red))
        else:
            c = index.data(Qt.DisplayRole+1) # Get the color
            painter.setBrush(QBrush(QColor(c)))

        # Draw the background rectangle            
        painter.drawRect(option.rect)

        # Draw the bottom border
        # option.rect is the shape of the item; top left bottom right
        # e.g. 0, 0, 256, 16 in the parent listwidget
        painter.setPen(QPen(Qt.red))        
        painter.drawLine(option.rect.bottomLeft(), option.rect.bottomRight())

        # Draw the text
        painter.setPen(QPen(Qt.black))
        text = index.data(Qt.DisplayRole)
        # Adjust the rect (to pad)
        option.rect.setLeft(5)
        option.rect.setRight(option.rect.right()-5)
        painter.drawText(option.rect, Qt.AlignLeft, text)

        painter.restore()


class MainWindow(QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        de = MyDelegate(self)
        w = QListWidget()
        w.setItemDelegate(de)
        for n in range(8):
            s = '%s' % n
            i = QListWidgetItem()
            i.setData(Qt.DisplayRole, s) # The label
            i.setData(Qt.DisplayRole+1, colors[n]) # The color
            w.addItem(i)

        self.setCentralWidget(w)

        self.show()


app = QApplication([])
w = MainWindow()
app.exec_()
</code></pre>

<p>Which gives the following output:</p>

<p><a href="https://i.stack.imgur.com/M9Y8R.png" rel="nofollow"><img src="https://i.stack.imgur.com/M9Y8R.png" alt="enter image description here"></a></p>

<p>The approach with delegates is to define a <code>paint</code> method, which accepts a <code>QPainter</code> object (with which you do the actual drawing), an <code>option</code> parameter containing the rectangle of the item (relative to the parent widget) and an <code>index</code> through which you can retrieve the item data. You then use the methods on the <a href="http://doc.qt.io/qt-4.8/qpainter.html" rel="nofollow">QPainter</a> to draw your item. </p>

<p>In the example above we use this to pass in both the item label (at position <code>Qt.DisplayRole</code>) and the color in hex (at position <code>Qt.DisplayRole+1</code>). The name docs for <a href="http://doc.qt.io/qt-4.8/qt.html#ItemDataRole-enum" rel="nofollow">ItemDisplayRole</a> list the other defined data 'roles', but for most purposes you can ignore these.</p>

python pyqt pyqt5