I have a QComboBox with a QStandardModel, to which I add items the following way:
QStandardItem * item = new QStandardItem();
item->setText("someText");
item->setCheckable(true);
item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
item->setData(Qt::Checked, Qt::CheckStateRole);
m_model->appendRow(item);
m_ComboBox->setModel(m_model);
Which gives me a combobox with checkboxes, which is exactly what I want. Now, when the user deselects all of the items, "None" should be the text of the dropdown menu. If the user selects some of the items, "Multiple" would be the text.
I haven't found a way on how to set the header text of a QComboBox. Is there no convenient way apart from subclassing and doing it on my own?
There is no convenient way to do it without subclassing. In fact, subclassing is the most convenient way.
Even if you could run through your QComboBox model and check which items are checked or not, you will have no way to tell your combo box to update itself once the items are all (or partially all) checked. There is no signal or particular function allowing you to do it.
But subclassing your QComboBox to have this behaviour is not very complex: you need to reimplement the paintEvent().
//return a list with all the checked indexes
QModelIndexList MyComboBox::checkedIndexes()const
{
return model()->match(model()->index(0, 0), Qt::CheckStateRole, Qt::Checked, -1, Qt::MatchRecursive);
}
// returns a list with all the unchecked indexes
QModelIndexList MyComboBox::uncheckedIndexes()const
{
return model()->match(model()->index(0, 0), Qt::CheckStateRole, Qt::Unchecked, -1, Qt::MatchRecursive);
}
//return true if all the items are checked
bool MyComboBox::allChecked()const
{
return (uncheckedIndexes().count() == 0);
}
//return true if all the items are unchecked
bool MyComboBox::noneChecked()const
{
return (checkedIndexes().count() == 0);
}
void MyComboBox::paintEvent(QPaintEvent *)
{
QStylePainter painter(this);
// draw the combobox frame, focusrect and selected etc.
QStyleOptionComboBox opt;
this->initStyleOption(&opt);
// all items are checked
if (allChecked())
opt.currentText = "All";
// none are checked
else if (noneChecked())
opt.currentText = "None";
//some are checked, some are not
else
opt.currentText = "Multiple";
painter.drawComplexControl(QStyle::CC_ComboBox, opt);
// draw the icon and text
painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
}
In case if someone what the implementation in python, use following code,
class CheckableComboBox(QtGui.QComboBox):
def __init__(self, parent=None):
super(CheckableComboBox, self).__init__(parent)
self.view().pressed.connect(self.handleItemPressed)
self._changed = False
def handleItemPressed(self, index):
item = self.model().itemFromIndex(index)
if item.checkState() == QtCore.Qt.Checked:
item.setCheckState(QtCore.Qt.Unchecked)
else:
item.setCheckState(QtCore.Qt.Checked)
self._changed = True
def hidePopup(self):
if not self._changed:
super(CheckableComboBox, self).hidePopup()
self._changed = False
def itemChecked(self, index):
item = self.model().item(index, self.modelColumn())
return item.checkState() == QtCore.Qt.Checked
def setItemChecked(self, index, checked=True):
item = self.model().item(index, self.modelColumn())
if checked:
item.setCheckState(QtCore.Qt.Checked)
else:
item.setCheckState(QtCore.Qt.Unchecked)
def checkedIndexes(self):
return self.model().match(self.model().index(0,0), QtCore.Qt.CheckStateRole, QtCore.Qt.Checked, -1, QtCore.Qt.MatchRecursive)
def uncheckedIndexes(self):
return self.model().match(self.model().index(0,0), QtCore.Qt.CheckStateRole, QtCore.Qt.Unchecked, -1, QtCore.Qt.MatchRecursive)
def allChecked(self):
return len(self.uncheckedIndexes()) == 0
def noneChecked(self):
return len(self.checkedIndexes()) == 0
def paintEvent(self, event):
painter = QtGui.QStylePainter(self)
opt = QtGui.QStyleOptionComboBox()
self.initStyleOption(opt)
if self.allChecked():
opt.currentText = "All"
elif self.noneChecked():
opt.currentText = "None"
else:
opt.currentText = "Multiple"
painter.drawComplexControl(QtGui.QStyle.CC_ComboBox, opt)
painter.drawControl(QtGui.QStyle.CE_ComboBoxLabel, opt)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With