QCompleter Custom Completion Rules

jcuenod picture jcuenod · Feb 26, 2011 · Viewed 12.5k times · Source

I'm using Qt4.6 and I have a QComboBox with a QCompleter in it.

The usual functionality is to provide completion hints (these can be in a dropdown rather than inline - which is my usage) based on a prefix. For example, given

chicken soup
chilli peppers
grilled chicken

entering ch would match chicken soup and chilli peppers but not grilled chicken.

What I want is to be able to enter ch and match all of them or, more specifically, chicken and match chicken soup and grilled chicken.
I also want to be able to assign a tag like chs to chicken soup to produce another match which is not just on the text's content. I can handle the algorithm but,

Which of QCompleter's functions do I need to override?
I'm not really sure where I should be looking...

Answer

Bruno picture Bruno · Oct 14, 2011

Based on @j3frea suggestion, here is a working example (using PySide). It appears that the model needs to be set every time splitPath is called (setting the proxy once in setModel doesn't work).

combobox.setEditable(True)
combobox.setInsertPolicy(QComboBox.NoInsert)

class CustomQCompleter(QCompleter):
    def __init__(self, parent=None):
        super(CustomQCompleter, self).__init__(parent)
        self.local_completion_prefix = ""
        self.source_model = None

    def setModel(self, model):
        self.source_model = model
        super(CustomQCompleter, self).setModel(self.source_model)

    def updateModel(self):
        local_completion_prefix = self.local_completion_prefix
        class InnerProxyModel(QSortFilterProxyModel):
            def filterAcceptsRow(self, sourceRow, sourceParent):
                index0 = self.sourceModel().index(sourceRow, 0, sourceParent)
                return local_completion_prefix.lower() in self.sourceModel().data(index0).lower()
        proxy_model = InnerProxyModel()
        proxy_model.setSourceModel(self.source_model)
        super(CustomQCompleter, self).setModel(proxy_model)

    def splitPath(self, path):
        self.local_completion_prefix = path
        self.updateModel()
        return ""


completer = CustomQCompleter(combobox)
completer.setCompletionMode(QCompleter.PopupCompletion)
completer.setModel(combobox.model())

combobox.setCompleter(completer)