To keep the GUI widgets number to minimum I need to find a way to give to user a choice of pull-down menu items that could be used to filter out the displayed in a listWidget items. Let's say the listWidget lists 5 different categories of Items: "Cat A", "Cat B","Cat C","Cat D","Cat E". I could implement the radio or checkboxes for each item category. But then 5 radio buttons or checkboxes would take a lot of GUI space. A combobox with the checkable items seems to be a right choice. Any ideas?
from PyQt4 import QtGui, QtCore
import sys, os
class CheckableComboBox(QtGui.QComboBox):
def __init__(self):
super(CheckableComboBox, self).__init__()
def flags(self, index):
return Qt.ItemIsUserCheckable | Qt.ItemIsSelectable | Qt.ItemIsEnabled
class Dialog_01(QtGui.QMainWindow):
def __init__(self):
super(QtGui.QMainWindow,self).__init__()
myQWidget = QtGui.QWidget()
myBoxLayout = QtGui.QVBoxLayout()
myQWidget.setLayout(myBoxLayout)
self.setCentralWidget(myQWidget)
self.ComboBox = CheckableComboBox()
for i in range(3):
self.ComboBox.addItem("Combobox Item " + str(i))
myBoxLayout.addWidget(self.ComboBox)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
dialog_1 = Dialog_01()
dialog_1.show()
dialog_1.resize(480,320)
sys.exit(app.exec_())
This idea of a multi-select combo has come up before, but I'm not sure that its the best solution. Really, all that's needed is a tool-button with a drop-down menu (similar to the history buttons in a web-browser).
Here's a basic demo that illustrates both options (button left, combo right):
PyQt5:
from PyQt5 import QtCore, QtGui, QtWidgets
class CheckableComboBox(QtWidgets.QComboBox):
def __init__(self, title = '', parent=None):
super().__init__(parent)
self.setTitle(title)
self.view().pressed.connect(self.handleItemPressed)
self.setModel(QtGui.QStandardItemModel(self))
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)
def title(self):
return self._title
def setTitle(self, title):
self._title = title
self.repaint()
def paintEvent(self, event):
painter = QtWidgets.QStylePainter(self)
painter.setPen(self.palette().color(QtGui.QPalette.Text))
opt = QtWidgets.QStyleOptionComboBox()
self.initStyleOption(opt)
opt.currentText = self._title
painter.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, opt)
painter.drawControl(QtWidgets.QStyle.CE_ComboBoxLabel, opt)
class Dialog(QtWidgets.QWidget):
def __init__(self):
super().__init__()
hbox = QtWidgets.QHBoxLayout()
self.comboBox = CheckableComboBox('Categories', self)
self.toolButton = QtWidgets.QToolButton(self)
self.toolButton.setText('Categories ')
self.toolMenu = QtWidgets.QMenu(self)
for index in range(3):
self.comboBox.addItem(f'Category {index}')
item = self.comboBox.model().item(index, 0)
item.setCheckState(QtCore.Qt.Unchecked)
action = self.toolMenu.addAction(f'Category {index}')
action.setCheckable(True)
self.toolButton.setMenu(self.toolMenu)
self.toolButton.setPopupMode(QtWidgets.QToolButton.InstantPopup)
hbox.addWidget(self.toolButton)
hbox.addWidget(self.comboBox)
layout = QtWidgets.QVBoxLayout(self)
layout.addLayout(hbox)
layout.addStretch()
if __name__ == '__main__':
app = QtWidgets.QApplication(['Test'])
dialog = Dialog()
dialog.show()
app.exec()
PyQt4:
from PyQt4 import QtCore, QtGui
class CheckableComboBox(QtGui.QComboBox):
def __init__(self, title = '', parent=None):
super().__init__(parent)
self.setTitle(title)
self.view().pressed.connect(self.handleItemPressed)
self.setModel(QtGui.QStandardItemModel(self))
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)
def title(self):
return self._title
def setTitle(self, title):
self._title = title
self.repaint()
def paintEvent(self, event):
painter = QtGui.QStylePainter(self)
painter.setPen(self.palette().color(QtGui.QPalette.Text))
opt = QtGui.QStyleOptionComboBox()
self.initStyleOption(opt)
opt.currentText = self._title
painter.drawComplexControl(QtGui.QStyle.CC_ComboBox, opt)
painter.drawControl(QtGui.QStyle.CE_ComboBoxLabel, opt)
class Dialog(QtGui.QWidget):
def __init__(self):
super().__init__()
hbox = QtGui.QHBoxLayout()
self.comboBox = CheckableComboBox('Categories', self)
self.toolButton = QtGui.QToolButton(self)
self.toolButton.setText('Categories ')
self.toolMenu = QtGui.QMenu(self)
for index in range(3):
self.comboBox.addItem('Category %s' % index)
item = self.comboBox.model().item(index, 0)
item.setCheckState(QtCore.Qt.Unchecked)
action = self.toolMenu.addAction('Category %s' % index)
action.setCheckable(True)
self.toolButton.setMenu(self.toolMenu)
self.toolButton.setPopupMode(QtGui.QToolButton.InstantPopup)
hbox.addWidget(self.toolButton)
hbox.addWidget(self.comboBox)
layout = QtGui.QVBoxLayout(self)
layout.addLayout(hbox)
layout.addStretch()
if __name__ == '__main__':
app = QtGui.QApplication(['Test'])
dialog = Dialog()
dialog.show()
app.exec()