基于@Bruno的回答,我正在使用标准的QSortFilterProxyModel
函数setFilterRegExp
来更改搜索字符串。这样就不需要子类化了。
它还修复了@Bruno答案中的一个错误,一旦输入字符串通过退格键进行校正,建议就会消失。
class CustomQCompleter(QtGui.QCompleter):
"""
adapted from: https://dev59.com/32435IYBdhLWcg3w7kyb#7767999
"""
def __init__(self, *args):
super(CustomQCompleter, self).__init__(*args)
self.local_completion_prefix = ""
self.source_model = None
self.filterProxyModel = QtGui.QSortFilterProxyModel(self)
self.usingOriginalModel = False
def setModel(self, model):
self.source_model = model
self.filterProxyModel = QtGui.QSortFilterProxyModel(self)
self.filterProxyModel.setSourceModel(self.source_model)
super(CustomQCompleter, self).setModel(self.filterProxyModel)
self.usingOriginalModel = True
def updateModel(self):
if not self.usingOriginalModel:
self.filterProxyModel.setSourceModel(self.source_model)
pattern = QtCore.QRegExp(self.local_completion_prefix,
QtCore.Qt.CaseInsensitive,
QtCore.QRegExp.FixedString)
self.filterProxyModel.setFilterRegExp(pattern)
def splitPath(self, path):
self.local_completion_prefix = path
self.updateModel()
if self.filterProxyModel.rowCount() == 0:
self.usingOriginalModel = False
self.filterProxyModel.setSourceModel(QtGui.QStringListModel([path]))
return [path]
return []
class AutoCompleteComboBox(QtGui.QComboBox):
def __init__(self, *args, **kwargs):
super(AutoCompleteComboBox, self).__init__(*args, **kwargs)
self.setEditable(True)
self.setInsertPolicy(self.NoInsert)
self.comp = CustomQCompleter(self)
self.comp.setCompletionMode(QtGui.QCompleter.PopupCompletion)
self.setCompleter(self.comp)
self.setModel(["Lola", "Lila", "Cola", 'Lothian'])
def setModel(self, strList):
self.clear()
self.insertItems(0, strList)
self.comp.setModel(self.model())
def focusInEvent(self, event):
self.clearEditText()
super(AutoCompleteComboBox, self).focusInEvent(event)
def keyPressEvent(self, event):
key = event.key()
if key == 16777220:
text = self.currentText()
self.setCompleter(None)
self.setEditText(text)
self.setCompleter(self.comp)
return super(AutoCompleteComboBox, self).keyPressEvent(event)
更新:
我发现我的先前解决方案仅在组合框中的字符串与列表项不匹配时才有效。然后,QFilterProxyModel
为空,这反过来又重置了组合框中的text
。我尝试找到一个优雅的解决方案来解决这个问题,但每当我尝试在self.filterProxyModel
上更改任何内容时,我都会遇到问题(引用已删除对象错误)。所以现在的方法是每当其模式更新时,设置self.filterProxyModel
的模型为新模型。并且每当模式不再与模型中的任何内容匹配时,将其替换为只包含当前文本(即splitPath
中的path
)的新模型。如果您处理非常大的模型,则可能会导致性能问题,但对于我来说,这个方法可以很好地工作。
更新 2:
我意识到这仍然不是最完美的方式,因为如果在组合框中键入新字符串并按enter键,组合框将再次被清除。输入新字符串的唯一方法是在键入后从下拉菜单中选择它。
更新 3:
现在按Enter键也可以了。我通过在用户按下Enter键时简单地将其取消来解决了组合框文本重置的问题。但我重新加回它,以保持完成功能的存在。如果用户决定进行进一步编辑。