Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. how to repaint a QComboBox ?
Forum Updated to NodeBB v4.3 + New Features

how to repaint a QComboBox ?

Scheduled Pinned Locked Moved Unsolved Qt for Python
3 Posts 2 Posters 1.5k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    alom
    wrote on 20 Jan 2020, 03:08 last edited by alom
    #1

    I'm trying to repaint a QCombobox, so I can control the text/arrow placement, along with multicolored text when an index changed from the 0.
    combobox_delegate.jpg

    I tried to subclass a QStyledItemDelegate and assign the custom delegate to a combobox. The custom delegate's paint() seems to only affect the popup listview in the combobox. What do I need to modify in order to repaint the Comboox itself? Is it an Editor? The documentation's "Detailed Description" on the QComboClass didn't help me understand how the combobox is made up, other than it has it's own listview for it's items.

    from PySide2 import QtGui, QtCore, QtWidgets
    
    class CustomComboDelegate(QtWidgets.QStyledItemDelegate):
        def __init__(self, parent=None):
            super(CustomComboDelegate, self).__init__(parent)
    
            self.text_default = QtGui.QColor(199, 199, 199)
            self.text_hover = QtGui.QColor(255, 255, 255)
            self.cell_default = QtGui.QColor(67, 67, 67)
            self.cell_hover = QtGui.QColor(43, 43, 43)
    
        def paint(self, painter, option, index):
            painter.save()
            value = index.data(QtCore.Qt.DisplayRole)
            painter.fillRect(option.rect, self.cell_default)
            painter.setPen(self.text_default)
            painter.drawText(option.rect, QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter, value)
            if option.state & QtWidgets.QStyle.State_MouseOver:
                painter.fillRect(option.rect, self.cell_hover)
                painter.setPen(self.text_default)
                painter.drawText(option.rect, QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter, value)
            painter.restore()
    
    
    app = QtWidgets.QApplication([])
    
    combo =  QtWidgets.QComboBox()
    combo.setItemDelegate(CustomComboDelegate(combo))
    combo.addItems(['one', 'two', 'three'])
    combo.show()
    app.exec_()
    

    Cheers

    1 Reply Last reply
    0
    • S Offline
      S Offline
      SGaist
      Lifetime Qt Champion
      wrote on 20 Jan 2020, 07:41 last edited by
      #2

      Hi,

      Depending on your goal, maybe using a style sheet would do the job.

      Otherwise, you will likely have to take a look at QComboBox sources to learn how the painting is done.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      1
      • A Offline
        A Offline
        alom
        wrote on 21 Jan 2020, 01:33 last edited by alom
        #3

        Cheers,
        Yeah I don't think stylesheets will get me where I would like to go. So it tried to subclass a combobox and override the paintEvent. I had a look at the source cpp and ~think i got it... :P

        seems to work atm, not sure how safe this approach is though. I still need to add the logic to repaint a changed selection:

        from PySide2 import QtGui, QtCore, QtWidgets
        
        
        class CustomComboDelegate(QtWidgets.QStyledItemDelegate):
            def __init__(self, parent=None):
                super(CustomComboDelegate, self).__init__(parent)
                self.text_default = QtGui.QColor(199, 199, 199)
                self.text_hover = QtGui.QColor(255, 255, 255)
                self.cell_default = QtGui.QColor(67, 67, 67)
                self.cell_hover = QtGui.QColor(43, 43, 43)
        
            def paint(self, painter, option, index):
                painter.save()
                value = index.data(QtCore.Qt.DisplayRole)
                painter.fillRect(option.rect, self.cell_default)
                painter.setPen(self.text_default)
                painter.drawText(option.rect, QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter, value)
                if option.state & QtWidgets.QStyle.State_MouseOver:
                    painter.fillRect(option.rect, self.cell_hover)
                    painter.setPen(self.text_default)
                    painter.drawText(option.rect, QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter, value)
                painter.restore()
        
        
        class CustomQComboBox(QtWidgets.QComboBox):
            def __init__(self, parent=None):
                super(CustomQComboBox, self).__init__(parent)
                self.__hovered = False
        
            def paintEvent(self, event):
                data = self.itemData(self.currentIndex(), QtCore.Qt.DisplayRole)
                if data:
                    p = QtWidgets.QStylePainter(self)
                    p.setPen(self.palette().color(QtGui.QPalette.Text))
                    opt = QtWidgets.QStyleOptionComboBox()
                    self.initStyleOption(opt)
                    p.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, opt)
                    painter = QtGui.QPainter(self)
                    painter.save()
                    pen = QtGui.QPen()
                    pen.setColor(QtGui.QColor(199, 199, 199))
                    if self.__hovered :
                        painter.fillRect(opt.rect, QtGui.QColor(43, 43, 43))
                        painter.setPen(QtCore.Qt.yellow)
                        painter.drawText(opt.rect.center(), data)
                        painter.setPen(QtCore.Qt.red)
                        painter.drawText(
                            opt.rect.center().x() + QtGui.QFontMetrics(painter.font()).size(QtCore.Qt.TextSingleLine,
                                                                                            data).width(),
                            opt.rect.center().y(), "(+)")
                    else:
                        painter.fillRect(opt.rect, QtGui.QColor(43, 43, 43))
                        painter.setPen(QtCore.Qt.yellow)
                        painter.drawText(opt.rect.center(), data)
                        painter.setPen(QtCore.Qt.red)
                    painter.restore()
        
                else:
                    super(CustomQComboBox, self).paintEvent(event)
        
            def mouseMoveEvent(self, event):
                if self.rect().contains(event.pos()):
                    self.__hovered = True
                super(CustomQComboBox, self).mouseMoveEvent(event)
        
            def leaveEvent(self, event):
                self.__hovered = False
                super(CustomQComboBox, self).leaveEvent(event)
        
        app = QtWidgets.QApplication([])
        
        combo = CustomQComboBox()
        combo.setMouseTracking(True)
        combo.setItemDelegate(CustomComboDelegate(combo))
        combo.addItems(['one', 'two', 'three'])
        combo.show()
        app.exec_()
        

        Is it worth to investigate setting up signals on the combobox to test the hover state and indexChanged or to manage this in the events? This is an area I'm not sure what methodology has the best performance/less maintenance

        1 Reply Last reply
        1

        2/3

        20 Jan 2020, 07:41

        • Login

        • Login or register to search.
        2 out of 3
        • First post
          2/3
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved