Checkboxes in a Combobox using PyQt
I need to implement a drop down list t开发者_StackOverflow社区hat contains CheckBoxes, much like having the entries in a ComboBox being CheckBoxes. But QComboBox doesn't accept QCheckBox as its member and I couldn't find any alternate solution. I found an implementation in C++ on the Qt Wiki, but don't know how to port it to python.
When i needed this, I come up with an easier solution (at least it is not necessary to subclass QCombobox). It worked for me. That is create a menu with checkable actions and set it to a button. Then connect either the menu or the actions to a slot.
The code in Qt(haven't use PyQt yet, sorry, i hope you can port that one, seems easier to me) was something like that:
QMenu *menu = new QMenu;
QAction *Act1 = new QAction("Action 1", menu);
Act1->setCheckable(true);
QAction *Act2 = new QAction("Action 2", menu);
Act2->setCheckable(true);
menu->addAction(Act1);
menu->addAction(Act2);
QPushButton *btn = new QPushButton("Btn");
btn->setMenu(menu);
Hope this helps
Use the Combobox item model, since items support checkBoxes you just need to mark the item to be checkable by the user, and set an initial checkState to make the checkBox appear (it does only show if there is a valid state)
item.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
item.setCheckState(QtCore.Qt.Unchecked) # causes checkBox to show
Here is a minimal subclass example:
from PyQt5 import QtGui, QtCore, QtWidgets
import sys, os
# subclass
class CheckableComboBox(QtWidgets.QComboBox):
# once there is a checkState set, it is rendered
# here we assume default Unchecked
def addItem(self, item):
super(CheckableComboBox, self).addItem(item)
item = self.model().item(self.count()-1,0)
item.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
item.setCheckState(QtCore.Qt.Unchecked)
def itemChecked(self, index):
item = self.model().item(i,0)
return item.checkState() == QtCore.Qt.Checked
# the basic main()
app = QtWidgets.QApplication(sys.argv)
dialog = QtWidgets.QMainWindow()
mainWidget = QtWidgets.QWidget()
dialog.setCentralWidget(mainWidget)
ComboBox = CheckableComboBox(mainWidget)
for i in range(6):
ComboBox.addItem("Combobox Item " + str(i))
dialog.show()
sys.exit(app.exec_())
I have replied a similar question at How do I create a tree view (with checkbox) inside a combo box - PyQt, but anyway and for completeness in the reply i paste you here:
You should create a model that support Qt.CheckStateRole in data and SetData methods and the flag Qt.ItemIsUserCheckable in the flags method.
I Paste you here an example i am using in a project, this is a QSortFilterProxyModel generic implementation to use in any model but you can use the same ideas in your model implementation, obviously i am using internal structures in this subclass you have not directly in PyQt and are attached to my internal implementation (self.booleanSet and self.readOnlySet).
def flags(self, index):
if not index.isValid():
return Qt.ItemIsEnabled
if index.column() in self.booleanSet:
return Qt.ItemIsUserCheckable | Qt.ItemIsSelectable | Qt.ItemIsEnabled
elif index.column() in self.readOnlySet:
return Qt.ItemIsSelectable | Qt.ItemIsEnabled
else:
return QSortFilterProxyModel.flags(self, index)
def data(self, index, role):
if not index.isValid():
return QVariant()
if index.column() in self.booleanSet and role in (Qt.CheckStateRole, Qt.DisplayRole):
if role == Qt.CheckStateRole:
value = QVariant(Qt.Checked) if index.data(Qt.EditRole).toBool() else QVariant(Qt.Unchecked)
return value
else: #if role == Qt.DisplayRole:
return QVariant()
else:
return QSortFilterProxyModel.data(self, index, role)
def setData(self, index, data, role):
if not index.isValid():
return False
if index.column() in self.booleanSet and role == Qt.CheckStateRole:
value = QVariant(True) if data.toInt()[0] == Qt.Checked else QVariant(False)
return QSortFilterProxyModel.setData(self, index, value, Qt.EditRole)
else:
return QSortFilterProxyModel.setData(self, index, data, role)
精彩评论