mirror of
https://github.com/Lerking/pyqt6-examples.git
synced 2025-07-20 23:21:05 +02:00
120 lines
4.0 KiB
Python
120 lines
4.0 KiB
Python
'''Checkable combobox'''
|
|
|
|
from PyQt6.QtWidgets import QComboBox, QStyledItemDelegate, QPalette
|
|
|
|
class CheckableComboBox(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)
|
|
# Make the lineedit the same color as QPushButton
|
|
palette = qApp.palette()
|
|
palette.setBrush(QPalette.Base, palette.button())
|
|
self.lineEdit().setPalette(palette)
|
|
|
|
# Use custom delegate
|
|
self.setItemDelegate(CheckableComboBox.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
|
|
|
|
# Prevent popup from closing when clicking on an item
|
|
self.view().viewport().installEventFilter(self)
|
|
|
|
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.MouseButtonRelease:
|
|
if self.closeOnLineEditClick:
|
|
self.hidePopup()
|
|
else:
|
|
self.showPopup()
|
|
return True
|
|
return False
|
|
|
|
if object == self.view().viewport():
|
|
if event.type() == QEvent.MouseButtonRelease:
|
|
index = self.view().indexAt(event.pos())
|
|
item = self.model().item(index.row())
|
|
|
|
if item.checkState() == Qt.Checked:
|
|
item.setCheckState(Qt.Unchecked)
|
|
else:
|
|
item.setCheckState(Qt.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.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.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.ItemIsEnabled | Qt.ItemIsUserCheckable)
|
|
item.setData(Qt.Unchecked, Qt.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):
|
|
# Return the list of selected items data
|
|
res = []
|
|
for i in range(self.model().rowCount()):
|
|
if self.model().item(i).checkState() == Qt.Checked:
|
|
res.append(self.model().item(i).data())
|
|
return res |