Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set different color to specifc items in QListWidget

Tags:

python

pyqt

pyqt5

I have a QListWidget 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 my_list.setStyleSheet("QListWidget::item { border-bottom: 1px solid red; background-color: blue;}") and to set background color to specific items I used item.setBackground(QtGui.QColor("#E3E3E3"))

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

like image 217
Oussama He Avatar asked Oct 12 '16 09:10

Oussama He


1 Answers

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 setBackground on each item to change the background colour.

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_()

The resulting output:

enter image description here

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

enter image description here enter image description here

Unfortunately, there is no way to set the border and the colour for the items. However, what you can do is either insert a custom widget as the list item, or use an item delegate 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:

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 & 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_()

Which gives the following output:

enter image description here

The approach with delegates is to define a paint method, which accepts a QPainter object (with which you do the actual drawing), an option parameter containing the rectangle of the item (relative to the parent widget) and an index through which you can retrieve the item data. You then use the methods on the QPainter to draw your item.

In the example above we use this to pass in both the item label (at position Qt.DisplayRole) and the color in hex (at position Qt.DisplayRole+1). The name docs for ItemDisplayRole list the other defined data 'roles', but for most purposes you can ignore these.

like image 193
mfitzp Avatar answered Oct 27 '22 11:10

mfitzp