PyQt: How to set Combobox Items be Checkable?

17,187

Solution 1

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 an update of the example that illustrates both options:

from PyQt4 import QtGui, QtCore
import sys, os

class CheckableComboBox(QtGui.QComboBox):
    def __init__(self):
        super(CheckableComboBox, self).__init__()
        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)

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))
            item = self.ComboBox.model().item(i, 0)
            item.setCheckState(QtCore.Qt.Unchecked)
        self.toolbutton = QtGui.QToolButton(self)
        self.toolbutton.setText('Select Categories ')
        self.toolmenu = QtGui.QMenu(self)
        for i in range(3):
            action = self.toolmenu.addAction("Category " + str(i))
            action.setCheckable(True)
        self.toolbutton.setMenu(self.toolmenu)
        self.toolbutton.setPopupMode(QtGui.QToolButton.InstantPopup)
        myBoxLayout.addWidget(self.toolbutton)
        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_())

Solution 2

It is very easy. Just set the item Checkable using the flags() function in the model associated with the comboBox.

def flags(self, index):
    return Qt.ItemIsUserCheckable | Qt.ItemIsSelectable | Qt.ItemIsEnabled

UPDATE


This may not be the best method, But it should sort your problem. Here is a something u may want look at , IF you have space restrictionn and cannot display the complete listView, Just resize it until it looks like a ComboBox.

enter image description here

Share:
17,187
alphanumeric
Author by

alphanumeric

Updated on June 08, 2022

Comments

  • alphanumeric
    alphanumeric almost 2 years

    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_())
    
  • alphanumeric
    alphanumeric about 10 years
    Just added it to the code. Thanks! I can't find a way to set multiple combobox items checked. Is it possible? I need multiple items to be checked at the same time...
  • thecreator232
    thecreator232 about 10 years
    i think that may not be possible because a combobox is used to select 1 option out of the list. I am not sure about it , i'll have to check it out.
  • thecreator232
    thecreator232 about 10 years
    @Sputnix : If you wish to check multiple options then ListView will be a better option.
  • alphanumeric
    alphanumeric about 10 years
    This looks very the same as I've envisioned it. Thanks Ekhumoro!
  • alphanumeric
    alphanumeric about 10 years
    If I use self.connect(action, QtCore.SIGNAL("triggered()"), self.myMethod) there are no args sent. It would make sense to submit a toolmenu's action as an arg to myMethod(self, arg). Would you mind showing how each action could be hooked to a method that would be used to receive an action as an arg (so an action's "checked" status could be verified (along with its name)? ("action" here is one of the instance name: result of action = self.toolmenu.addAction("Category " + str(i))
  • ekhumoro
    ekhumoro about 10 years
    @Sputnix. Just connect to the triggered signal of the tool-menu - it sends the action which was triggered. Also, you can iterate over the actions of the menu using its actions method.
  • alphanumeric
    alphanumeric about 10 years
    Thanks! Almost there!
  • alphanumeric
    alphanumeric about 10 years
    If no .addAction() actions were added to QMenu then clicking on QToolButton brings a Warining: void QCocoaWindow::syncWindowState(Qt::WindowState) invalid window content view size, check your window geometry I wonder if it is a .setPopupMode method that triggers it? Should be QtGui.QToolButton "unset" from .setPopupMode(QtGui.QToolButton.InstantPopup) if there are no actions connected?
  • ekhumoro
    ekhumoro about 10 years
    @Sputnix. Not sure, because I can't test on OSX (I don't get any errors on Linux). Maybe you should only set the menu on the button once you have actions to add to it.
  • alphanumeric
    alphanumeric about 10 years
    Thanks! If I figure this out I'll let you know. Otherwise it works great! Thanks again!
  • alphanumeric
    alphanumeric about 10 years
    Agree. But I have too little GUI space for that one.