Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QComboBox checkbox indicator overwrites left of Item text in Windows11 pyqt6 but not on Ubuntu
QtWS25 Last Chance

QComboBox checkbox indicator overwrites left of Item text in Windows11 pyqt6 but not on Ubuntu

Scheduled Pinned Locked Moved Unsolved General and Desktop
qcombobox
2 Posts 2 Posters 236 Views
  • 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.
  • V Offline
    V Offline
    VolkerH
    wrote on last edited by
    #1

    I am using a 'CheckableComboBox' widget in Python pyqt6, which works fine in Ubuntu, but in Windows 11 the ComboBox indicator seems to be hard coded to overwrite the left edge of the Item text. If you use a CSS style to vary the padding, right and left offsets etc. of the indicator then the styled indicator moves around as you program it to, but the displayed item text in the GUI has a locked in blank overlay at its left edge as though there is a default checkbox lurking there.

    Windows and Linux renderings of the same combobox

    Code -

    -- coding: utf-8 --

    From https://gis.stackexchange.com/questions/350148/qcombobox-multiple-selection-pyqt5

    import sys
    from PyQt6.QtCore import Qt, QEvent
    from PyQt6.QtGui import QStandardItem, QFontMetrics
    from PyQt6.QtWidgets import ( QComboBox, QStyledItemDelegate,
    QSizePolicy,
    QApplication,
    QMainWindow,
    QWidget )

    class MultiComboBox(QComboBox):
    # Subclass Delegate to increase item height
    class Delegate(QStyledItemDelegate):
    def sizeHint(self, option, index):
    size = super().sizeHint(option, index)
    size.setHeight(20)
    return size

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
    
        # Make the combo editable to set a custom text, but readonly
        self.setEditable(True)
        self.lineEdit().setReadOnly(True)
    
        # Use custom delegate
        self.setItemDelegate(MultiComboBox.Delegate())
    
        # Update the text when an item is toggled
        self.model().dataChanged.connect(self.updateText)
    
        # Hide and show popup when clicking the line edit
        self.lineEdit().installEventFilter(self)
        self.closeOnLineEditClick = False
    
    def resizeEvent(self, event):
        # Recompute text to elide as needed
        self.updateText()
        super().resizeEvent(event)
    
    def eventFilter(self, object, event):
        if object == self.lineEdit():
            if event.type() == QEvent.Type.MouseButtonRelease:
                if self.closeOnLineEditClick:
                    self.hidePopup()
                else:
                    self.showPopup()
                return True
            return False
    
        if object == self.view().viewport():
            if event.type() == QEvent.Type.MouseButtonRelease:
                index = self.view().indexAt(event.pos())
                item = self.model().item(index.row())
    
                if item.checkState() == Qt.CheckState.Checked:
                    item.setCheckState(Qt.CheckState.Unchecked)
                else:
                    item.setCheckState(Qt.CheckState.Checked)
                return True
        return False
    
    def showPopup(self):
        super().showPopup()
        # When the popup is displayed, a click on the lineedit should close it
        self.closeOnLineEditClick = True
    
    def hidePopup(self):
        super().hidePopup()
        # Used to prevent immediate reopening when clicking on the lineEdit
        self.startTimer(100)
        # Refresh the display text when closing
        self.updateText()
    
    def timerEvent(self, event):
        # After timeout, kill timer, and reenable click on line edit
        self.killTimer(event.timerId())
        self.closeOnLineEditClick = False
    
    def updateText(self):
        texts = []
        for i in range(self.model().rowCount()):
            if self.model().item(i).checkState() == Qt.CheckState.Checked:
                texts.append(self.model().item(i).text())
        text = ", ".join(texts)
    
        # Compute elided text (with "...")
        metrics = QFontMetrics(self.lineEdit().font())
        elidedText = metrics.elidedText(text, Qt.TextElideMode.ElideRight, self.lineEdit().width())
        self.lineEdit().setText(elidedText)
    
    def addItem(self, text, data=None):
        item = QStandardItem()
        item.setText(text)
        if data is None:
            item.setData(text)
        else:
            item.setData(data)
        item.setFlags(Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsUserCheckable)
        item.setData(Qt.CheckState.Unchecked, Qt.ItemDataRole.CheckStateRole)
        self.model().appendRow(item)
    
    def addItems(self, texts, datalist=None):
        for i, text in enumerate(texts):
            try:
                data = datalist[i]
            except (TypeError, IndexError):
                data = None
            self.addItem(text, data)
    
    def currentData(self):
        res = []
        for i in range(self.model().rowCount()):
            if self.model().item(i).checkState() == Qt.CheckState.Checked:
                res.append(self.model().item(i).data())
        return res
    
    def currentOptions(self):
        res = []
        for i in range(self.model().rowCount()):
            if self.model().item(i).checkState() == Qt.CheckState.Checked:
                res.append((self.model().item(i).text(),
                            self.model().item(i).data()))
        return res
    

    comunes = ['Ameglia', 'Arcola', 'Bagnone', 'Bolano', 'Melbourne', 'Othertown' ]
    cStyle = """
    QComboBox QAbstractItemView{ background-color: #ccccff; border: 1px solid yellow; }
    QAbstractItemView::indicator{ border: 1px solid blue; background-color: transparent; }
    QAbstractItemView::indicator:checked{ border: 1px solid red; background-color: orange; }
    """
    cStyleWithOffset = """
    QComboBox QAbstractItemView{ background-color: #ccccff; border: 1px solid yellow; padding-left: 20px; }
    QAbstractItemView::indicator{ border: 1px solid blue; background-color: transparent; left: -10px; }
    QAbstractItemView::indicator:checked{ border: 1px solid red; background-color: orange; }
    """
    qtApp = QApplication( sys.argv )
    qWin = QMainWindow()
    combo = MultiComboBox( parent=qWin )
    combo.addItems( comunes )
    combo.setMinimumWidth( 300 )

    combo.setStyleSheet( cStyle )

    combo.setStyleSheet( cStyleWithOffset )
    qWin.show()
    qtApp.exec()

    1 Reply Last reply
    0
    • Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #2

      What exact Qt version do you use?
      I would guess it's 6.7.0 or similar with the new windows11 style which has some bugs. Either upgrade to 6.8.x or use the windowsvista style in between.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      1 Reply Last reply
      0

      • Login

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