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.
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:
However, if we add the stylesheet line in the result is (and second with only the bottom border):
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With