pythonpyqt5qcomboboxmutual-exclusion

How to make a QComboBox group mutually exclusive?


Once an item is selected on a combo, it should get removed from the others, unless it's "No use".

I made three options of QComboBox, and each of those contains the same items.

The explanation is this:

The default value of those Qcombobox is 'No Use'.

How can I remove the selected value of QComboBox Tug 1 from QComboBox Tug 2?

The point is that 'No Use' shall not be removed; only an item from among '207HR', '306DR', and 'Jupiter'.

The Code i made is below:

class Ship_Use_Tug_Input_Program(QWidget):
    def __init__(self, master):
        super().__init__()
        self.initUI()

    def initUI(self):
        tug1_cb = QComboBox(self)
        jeju_tug = ['No use','207HR (2,500HP)', '306DR (3,600HP)', 'Jupiter (3,600HP)']
        tug1_cb.addItems(jeju_tug)

        tug2_cb = QComboBox(self)
        tug2_cb.addItems(jeju_tug)

        tug3_cb = QComboBox(self)
        tug3_cb.addItems(jeju_tug)

        self.setGeometry(100,100,1000,500) 
        self.setWindowTitle('Ship_Use_Tug_Input_Program')
        self.show()
app = QApplication(sys.argv)
exc = Ship_Use_Tug_Input_Program(master=Ship_Use_Tug_Input_Program)
app.exec_()

The explanation photo is below: enter image description here


Solution

  • The view-widget of the combo-box can be used to hide the rows, and the item-data can be used to keep track of which combo-box is showing which row. A slot connected to the activated signal can then update the items whenever one of the current-items change.

    Below is a complete demo script that implements that. The ExclusiveComboGroup class can be used with any group of combo-boxes. To use it, just create an instance and then add all your combo-boxes using its addCombo method.

    enter image description here

    Demo Script:

    import sys
    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import *
    
    class ExclusiveComboGroup(QObject):
        def __init__(self, parent=None):
            super().__init__(parent)
            self._combos = []
            self._role = Qt.UserRole + 500
    
        def addCombo(self, combo):
            combo.activated.connect(
                lambda: self.handleActivated(combo))
            self._combos.append(combo)
    
        def handleActivated(self, target):
            index = target.currentIndex()
            groupid = id(target)
            for combo in self._combos:
                if combo is target:
                    continue
                previous = combo.findData(groupid, self._role)
                if previous >= 0:
                    combo.view().setRowHidden(previous, False)
                    combo.setItemData(previous, None, self._role)
                if index > 0:
                    combo.setItemData(index, groupid, self._role)
                    combo.view().setRowHidden(index, True)
    
    class Window(QWidget):
        def __init__(self):
            super().__init__()
            self.group = QGroupBox('Selected Tug')
            layout = QVBoxLayout(self)
            layout.addWidget(self.group)
            layout = QFormLayout(self.group)
            layout.setVerticalSpacing(15)
            layout.setHorizontalSpacing(50)
            jeju_tug = [
                'No use',
                '207HR (2,500HP)',
                '306DR (3,600HP)',
                'Jupiter (3,600HP)',
                ]
            # create a combo-group
            self.tugs = ExclusiveComboGroup(self)
            for index in range(3):
                combo = QComboBox(self)
                combo.addItems(jeju_tug)
                layout.addRow(f'Tug {index + 1}', combo)
                # add the combo-box
                self.tugs.addCombo(combo)
    
    if __name__ == "__main__":
    
        app = QApplication(sys.argv)
        window = Window()
        window.setWindowTitle('Demo')
        window.setGeometry(800, 200, 100, 50)
        window.show()
        sys.exit(app.exec_())
    

    PS: here is how to use it in your own example:

    def initUI(self):
        tug1_cb = QComboBox(self)
        jeju_tug = ['No use','207HR (2,500HP)', '306DR (3,600HP)', 'Jupiter (3,600HP)']
        tug1_cb.addItems(jeju_tug)
    
        tug2_cb = QComboBox(self)
        tug2_cb.addItems(jeju_tug)
    
        tug3_cb = QComboBox(self)
        tug3_cb.addItems(jeju_tug)
        
        # copy the ExclusiveComboGroup class into
        # your code and then add this section
        tugs = ExclusiveComboGroup(self)
        tugs.addCombo(tug1_cb)
        tugs.addCombo(tug2_cb)
        tugs.addCombo(tug3_cb)