Search code examples
pythonautocompletepyside2qlineeditqcompleter

Autocomplete from start of (one of) multiple columns


I have data with multiple columns (like "first name"/"surname" or "postal code"/"place name"), and I would now like to have (something like) a qcompleter which only matches from the start of each column.

This means an input of "a" would show the suggestions like "Andrea Miller" or "John Adams" but not "Jane Doe" or "Tom Masters".

Any hints how to implements this?


Solution

  • A workaround is to disable QCompleter filtering and use a QSortFilterProxyModel to do custom filtering:

    import sys
    
    
    from PySide2 import QtCore, QtWidgets
    
    
    class FilterModel(QtCore.QSortFilterProxyModel):
        def __init__(self, parent=None):
            super().__init__(parent)
            self._prefix = ""
    
        @property
        def prefix(self):
            return self._prefix
    
        @prefix.setter
        def prefix(self, prefix):
            self._prefix = prefix.lower()
            self.invalidateFilter()
    
        def filterAcceptsRow(self, sourceRow, sourceParent):
            if not self.prefix:
                return True
            text = (
                self.sourceModel()
                .index(sourceRow, self.filterKeyColumn(), sourceParent)
                .data()
            )
            for word in text.split():
                if word.lower().startswith(self.prefix):
                    return True
            return False
    
    
    class Completer(QtWidgets.QCompleter):
        def setModel(self, model):
            proxy_internal_model = FilterModel(self)
            proxy_internal_model.setSourceModel(model)
            model.setParent(proxy_internal_model)
            super().setModel(proxy_internal_model)
    
        def splitPath(self, path):
            if isinstance(self.model(), FilterModel):
                self.model().prefix = path
            return [""]
    
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        w = QtWidgets.QLineEdit()
        texts = ["Andrea Miller", "John Adams", "Jane Doe", "Tom Masters"]
        completer = Completer(w)
        completer.setModel(QtCore.QStringListModel(texts, w))
        w.setCompleter(completer)
        w.show()
        sys.exit(app.exec_())