'Not being able to have two QComboBox with the same item
I have a list that contains all the drivers from a F1 season:
drivers = ['ALO', 'BOT', 'GAS', 'GIO', 'HAM', 'KUB', 'LAT', 'LEC', 'MAZ', 'NOR', 'OCO', 'PER', 'RAI', 'RIC', 'RUS', 'SAI', 'MSC', 'STR', 'TSU', 'VER', 'VET']
And two QComboBox that I load with that list
self.comboDrivers_1.addItems(drivers)
self.comboDrivers_2.addItems(drivers)
I want the QComboBox not to contain the item that the other one has.
Maybe is there a way to hide temporarily a item, and show again whenever the other QComboBox change its value?
Solution 1:[1]
Depending on the situation, there are various options available.
For a basic items[x] -> items[without x] case (and vice versa), a viable option is to use combined pairs of QSortFilterProxyModel.
The background is to create a basic source model containing all items, and set a QSortFilterProxyModel for each combo that will eventually be filtered depending on the other selected index.
The drawback of this approach is that the currentIndex of each combo box can never be used as a proper one in the items' indexes: if index 0 is hidden, the combo's index 0 will be the second one. This must be considered for all signals that use the combo index as argument, including currentIndexChanged.
That said, you can still get the currentText() of the selected combo.
from PyQt5 import QtWidgets, QtCore
Drivers = [
'ALO', 'BOT', 'GAS', 'GIO',
'HAM', 'KUB', 'LAT', 'LEC',
'MAZ', 'NOR', 'OCO', 'PER',
'RAI', 'RIC', 'RUS', 'SAI',
'MSC', 'STR', 'TSU', 'VER', 'VET'
]
DriverRole = QtCore.Qt.UserRole + 1
class ProxyDriverModel(QtCore.QSortFilterProxyModel):
ignoreIndex = -1
def __init__(self):
super().__init__()
self.setSourceModel(QtCore.QStringListModel(Drivers))
def setIgnoreIndex(self, index):
if self.ignoreIndex != index:
self.ignoreIndex = index
self.invalidateFilter()
def data(self, index, role=DriverRole):
if role == DriverRole:
# return the original index for the row based on the source data
return self.mapToSource(index).row()
return super().data(index, role)
def filterAcceptsRow(self, row, parent):
# ignore the *source* row if it matches the ignoreIndex
return row != self.ignoreIndex
class Test(QtWidgets.QWidget):
def __init__(self):
super().__init__()
layout = QtWidgets.QHBoxLayout(self)
self.comboDrivers_1 = QtWidgets.QComboBox()
self.comboDrivers_2 = QtWidgets.QComboBox()
layout.addWidget(self.comboDrivers_1)
layout.addWidget(self.comboDrivers_2)
self.comboModel1 = ProxyDriverModel()
self.comboModel2 = ProxyDriverModel()
self.comboDrivers_1.setModel(self.comboModel1)
self.comboDrivers_2.setModel(self.comboModel2)
self.comboDrivers_1.currentIndexChanged.connect(self.updateCombo1)
self.comboDrivers_2.currentIndexChanged.connect(self.updateCombo2)
# ensure we "reset" the combo index to an invalid one for the filtered
# model that is used on the combo
# (note: this MUST be done AFTER connecting signals of both combos)
self.comboDrivers_1.setCurrentIndex(-1)
# set the current index to the wanted one
self.comboDrivers_1.setCurrentIndex(0)
def updateCombo1(self, index):
driverIndex = self.comboDrivers_1.itemData(index, DriverRole)
self.comboModel2.setIgnoreIndex(driverIndex)
def updateCombo2(self, index):
driverIndex = self.comboDrivers_2.itemData(index, DriverRole)
self.comboModel1.setIgnoreIndex(driverIndex)
app = QtWidgets.QApplication([])
test = Test()
test.show()
app.exec()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | musicamante |
