'PyQt5: How to bold the placeholder of a QComboBox?

Well as the title already tells, I want to bold the placeholder text of a QComboBox. I can't see a way to bold the placeholder of a QComboBox. With QFont i can bold every item in the QComboBox, but I just want the placeholder being bold. setPlaceholderText() takes only one argument for the text itself.

My current code:

comboBox = QComboBox()
# - Bold whole combobox- 
# font = QFont()
# font.setBold(True)
# comboBox.setFont(font) 
comboBox.addItems(items)
comboBox.setPlaceholderText("Select text")
comboBox.setCurrentIndex(-1)

Thanks in advance.



Solution 1:[1]

QComboBox doesn't provide so, and there are only two possibilities:

  1. use a QProxyStyle and override drawControl() whenever a CE_ComboBoxLabel is being drawn, by checking if the combo has an invalid index and a place holder text;
class ComboStyle(QtWidgets.QProxyStyle):
    def drawControl(self, ce, opt, qp, widget=None):
        if (ce == self.CE_ComboBoxLabel and 
            widget.currentIndex() < 0 and 
            widget.placeholderText()):
                qp.save()
                font = widget.font()
                font.setBold(True)
                qp.setFont(font)
                super().drawControl(ce, opt, qp, widget)
                qp.restore()
        else:
            super().drawControl(ce, opt, qp, widget)

# ...
app.setStyle(ComboStyle())
# or, alternatively
combo.setStyle(ComboStyle())
  1. use a subclass and change the font depending on the situations:
class ComboBox(QtWidgets.QComboBox):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._defaultFont = self.font()
        self._boldFont = self.font()
        self._boldFont.setBold(True)
        self.currentIndexChanged.connect(self.checkFont)
        self.checkFont(self.currentIndex())

    def checkFont(self, index):
        if index < 0 and self.placeholderText():
            self.setFont(self._boldFont)
        else:
            self.setFont(self._defaultFont)

    def setPlaceholderText(self, placeholderText):
        super().setPlaceholderText(placeholderText)
        self.checkFont(self.currentIndex())

    def showPopup(self):
        self.setFont(self._defaultFont)
        super().showPopup()

    def hidePopup(self):
        super().hidePopup()
        self.checkFont(self.currentIndex())

NOTE: Due to a bug in the latest Qt5 release (which was fixed for the commercial version of Qt, but it's not clear if it will be released for the open source version too), I've not been able to test the above.

Solution 2:[2]

Solution

Due of a bug in the library, QComboBox has to be overwritten in order to set a placeholder. I already had the class for overwriting QComboBox so I did a minor change to make the placeholderText bold.

class QComboBox(QComboBox):

    def __init__(self, boldPlaceholder: bool = False, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.boldPlaceholder = boldPlaceholder


    def paintEvent(self, event):
        painter = QStylePainter(self)
        painter.setPen(self.palette().color(QPalette.Text))

        # draw the combobox frame, focusrect and selected etc.
        opt = QStyleOptionComboBox()
        self.initStyleOption(opt)
        painter.drawComplexControl(QStyle.CC_ComboBox, opt)

        if self.currentIndex() < 0:
            opt.palette.setBrush(
                QPalette.ButtonText,
                opt.palette.brush(QPalette.ButtonText).color().lighter()
            )

            if self.placeholderText():
                opt.currentText = self.placeholderText()

            # bold placeholdertText
            if self.boldPlaceholder and self.placeholderText():
                font = self.font()
                font.setBold(True)
                painter.setFont(font)


        # draw the icon and text
        painter.drawControl(QStyle.CE_ComboBoxLabel, opt)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 musicamante
Solution 2 puncher