QComboBox checkbox indicator overwrites left of Item text in Windows11 pyqt6 but not on Ubuntu
-
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.
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 sizedef __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() -
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.