Selecting and filtering unique entries from a list using QComboBoxes

190 Views Asked by At

I have a shortlist (no more then ten or so items) that I want a user to match against another list. The order may be random and they may re-assign any value as they see fit. I want to indicate values already assigned but not necessarily prevent their re-assignment. How would one achieve this in Qt ? (Preferably PyQt but cpp is good too.)

These requirements indicate that one should use the QSortFilterProxyModel which proxies a QListItemModel (QAbstractItemListModel) and possibly a QSelectionModel.

As an example lets argue that we have the categories First, Second and Third Language. We have the options English, Afrikaans, German, Dutch and Russian. We would expect the user to assign say Afrikaans to first, English to second and German to the Third Language boxes. Later they may decide they speak better Russian then say Afrikaans and want to change the first block again. Alternatively they may want to swap German and English.

My first bash at this is as follows :

from PyQt5 import QtGui, QtWidgets, QtCore

class QListModel(QtCore.QAbstractListModel) :

 def __init__(self, *args, data = [], **kvps):
  super().__init__(*args, **kvps) 
  self.update(data)

 def rowCount(self, index):
  return len(self._data_)

 def update(self, data = []):
  self._data_ = data

 def data(self, index, role = QtCore.Qt.DisplayRole) :
  if not index.isValid() : 
   print('inValid')
  object = self._data_[index.row()]
  roles = { 0:str(object),    # object.text(row,col)
   }
  if role in roles.keys() :
   return roles[role]
  else :
   return None   

def main(data) :
 app   = QtWidgets.QApplication(sys.argv)
 main  = QtWidgets.QMainWindow()
 cntr  = QtWidgets.QWidget(main)
 hbox  = QtWidgets.QHBoxLayout(cntr)
 vbox  = QtWidgets.QVBoxLayout(cntr)
 model = QListModel(data = data) 
 proxy = QtCore.QSortFilterProxyModel()
 proxy.setSourceModel(model)
 enum  = QtWidgets.QListView(main)
 enum.setModel(proxy)
 select = enum.selectionModel()
 combos = [QtWidgets.QComboBox(main) for i in range(3)]
 [item.setModel(proxy) for item in combos]
 [item.view().setSelectionModel(select) for item in combos]
 [vbox.addWidget(item) for item in combos]
 hbox.addLayout(vbox)
 hbox.addWidget(enum)
 main.setCentralWidget(cntr)
 main.show()
 app.exec_()

if __name__ == "__main__" :
 import sys # Move
 main(['','English','Afrikaans','Russian','German','Dutch'])

This uses a single list between the different combo's. The list on the right is to visualize what's potting when I make a selection. What I feel is missing is the highlighting of selected options within the Comboboxes.

I am considering the following approach :

Allow each combobox to have it's own selection model and feed the selectionChanged signals into a separate selection model (in this case the one for the list) which would retain/manage the entire selection. There is a problem in how one then updates the selections when one combobox picks another comboboxes' option. I also can not see how the selection would feed back to the model, ideally one would disable an option once it was selected or atleast indicate it's been selected elsewhere. Is it possible to feed the active selection into a QSortFilterProxy, using the active selection to modify the appearance of data in the different comboboxes ?

0

There are 0 best solutions below