skip to Main Content

I would like to be able to select multiple QComboBox‘s items from its pull-down menu (with Shift or Alt+click to add/extract to-from current selection).

  1. On a click QComboBox rolls down a pull-down menu.

  2. But when the user makes a second mouse click (picking an item from pull-down menu)

ComboBox wouldn’t roll-back (or self-collapse) as it does by default. Instead it would stay open so the user is able to Shift+click more Combobox items to add or to extract them from selection. Finally when the user is happy with the selection the Enter key is pressed to “confirm” the selection.

Here is a Photoshoped image showing the concept of “multi-selection” QComboBox I would like to achieve:

enter image description here

The code below creates QComboBox with almost every event exposed. But the only one I see “acting” is onMousePressEvent(). I can’t find the way to track down when the user selects the item from pull-down menu….

Edit:

Hour later I learned that QComboBox can be set to multi selection via its .view().setSelectionMode(3).

Then the same .view() could be used to query Combobox selected items:

selectedIndexes=self.view().selectionModel().selectedIndexes() 

(where self is a combo itself)

There is a way to select the Combo items using selectionModel.select(idx, QtGui.QItemSelectionModel.Select)

But so far I was not able to make it…..

from PyQt4 import QtCore, QtGui

app = QtGui.QApplication([])
class Combo(QtGui.QComboBox):
    def __init__(self, *args, **kwargs):
        super(Combo, self).__init__()
        self.addItems(['Item_1','Item_2','Item_3','Item_4','Item_5'])
        self.view=self.view()
        self.view.setSelectionMode(3)
        self.activated.connect(self.clicked)   
        self.show()

    def clicked(self, arg=None):
        selectionModel=self.view.selectionModel()
        selectedIndexes=selectionModel.selectedIndexes()

        for idx in selectedIndexes:
            selectionModel.select(idx, QtGui.QItemSelectionModel.Select)
            print 'selecting idx: %s'%idx

        self.showPopup()

tree=Combo()
sys.exit(app.exec_())

2

Answers


  1. Chosen as BEST ANSWER

    I ended up using the text colors to differentiate clicked (aka selected) items from others.

    First click on ComboBox opens its pull-down menu. All following clicks are to select/deselect (highlighted red) items. Hit escape to close pull-down.

    enter image description here

    from PyQt4 import QtCore, QtGui
    app = QtGui.QApplication([])
    
    class Combo(QtGui.QComboBox):
        def __init__(self, *args, **kwargs):
            super(Combo, self).__init__()        
            for each in ['Item_1','Item_2','Item_3','Item_4','Item_5']:
                item=QtGui.QStandardItem(each) 
                self.model().appendRow(item)
                item.setData('black')
    
            self.activated.connect(self.clicked)   
            self.show()  
    
        def clicked(self, clickedNumber=None): 
            self.blockSignals(True)  
            self.setCurrentIndex(0)        
            self.showPopup()
            self.view().clearSelection()
    
            clickedItem=self.model().item(clickedNumber)
    
            color=clickedItem.data().toString()
            if color=='black': clickedItem.setData('red')
            elif color=='red': clickedItem.setData('black')
            clickedItem.setForeground(QtGui.QColor(clickedItem.data().toString()))
    
            clickedIndex=self.model().indexFromItem(clickedItem)
            self.view().selectionModel().select(clickedIndex, QtGui.QItemSelectionModel.Select)
            self.setCurrentIndex(clickedNumber)  
    
            self.blockSignals(False)
    
    tree=Combo()
    sys.exit(app.exec_())
    

  2. Other way, your can use just-like icon to check state. To easy than QtGui.QStandardItem. The method QIcon QComboBox.itemIcon (self, int index) and method QComboBox.setItemIcon (self, int index, QIcon icon) are available in class QtGui.QComboBox;

    import sys
    from PyQt4 import QtGui
    
    class QCustomComboBox (QtGui.QComboBox):
        CHECK_QICON   = QtGui.QIcon.fromTheme('call-start')
        UNCHECK_QICON = QtGui.QIcon.fromTheme('call-stop')
    
        def __init__(self, *args, **kwargs):
            super(QCustomComboBox, self).__init__(*args, **kwargs)
            listsItem = ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5']
            for index in range(0, len(listsItem)):
                self.addItem(listsItem[index])
                self.setItemIcon(index, self.UNCHECK_QICON)
            self.activated.connect(self.customActivated)
    
        def hidePopup (self):
            pass # Force only ESC button to exit.
    
        def customActivated (self, index):
            # self.blockSignals(True) # Force first index only
            # self.setCurrentIndex(0)
            # self.blockSignals(False)
            stateQIcon = self.itemIcon(index)
            newQIcon = {
                self.CHECK_QICON.name()   : self.UNCHECK_QICON,
                self.UNCHECK_QICON.name() : self.CHECK_QICON,
            } [stateQIcon.name()]
            self.setItemIcon(index, newQIcon)
            print self.export() # View last update data
    
        def export (self):
            listsExportItem = []
            for index in range(0, self.count()):
                stateQIcon = self.itemIcon(index)
                state = {
                    self.CHECK_QICON.name()   : True,
                    self.UNCHECK_QICON.name() : False,
                } [stateQIcon.name()]
                listsExportItem.append([str(self.itemText(index)), state])
            return listsExportItem
    
    myQApplication = QtGui.QApplication([])
    myQCustomComboBox = QCustomComboBox()
    myQCustomComboBox.show()
    sys.exit(myQApplication.exec_())
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search