PyQt5可过滤ComboBox问题:仅匹配开头,无法匹配字符串内部
问题:PyQt5 FilterComboBox仅匹配选项开头,无法匹配任意部分
我刚接触Python,之前学过Cobol和Pascal,可能有些旧习惯。我使用Python 3.11和PyQt5实现了一个FilterComboBox类,期望用户输入时,只要输入文本匹配下拉框选项的任意部分就进行过滤,但当前代码仅在匹配选项开头时生效,无法匹配字符串内部的内容。
原代码:
class FilterComboBox(QtWidgets.QComboBox): def __init__(self, parent=None): super(FilterComboBox, self).__init__(parent) self.setFocusPolicy(QtCore.Qt.StrongFocus) self.setEditable(True) # add a filter model to filter matching items self.pFilterModel = QtCore.QSortFilterProxyModel(self) self.pFilterModel.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive) # add a completer, which uses the filter model self.completer = QtWidgets.QCompleter(self.pFilterModel, self) # filter the completions self.completer.setCompletionMode(QtWidgets.QCompleter.PopupCompletion) self.setCompleter(self.completer) # connect signals self.lineEdit().textEdited.connect(self.on_lineEdit_textEdited) self.completer.activated.connect(self.on_completer_activated) def on_lineEdit_textEdited(self, text): regex = QtCore.QRegExp(".*" + text + ".*", QtCore.Qt.CaseInsensitive, QtCore.QRegExp.RegExp) self.pFilterModel.setFilterRegExp(regex) # on selection of an item from the completer, select the corresponding item from combobox def on_completer_activated(self, text): if text: index = self.findText(text) self.setCurrentIndex(index) self.activated[str].emit(self.itemText(index)) # on model change, update the models of the filter and the completer as well def setModel(self, model): super(FilterComboBox, self).__init__(parent) self.setFocusPolicy(QtCore.Qt.StrongFocus) self.setEditable(True) # add a filter model to filter matching items self.pFilterModel = QtCore.QSortFilterProxyModel(self) self.pFilterModel.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive) # add a completer, which uses the filter model self.completer = QtWidgets.QCompleter(self.pFilterModel, self) # filter the completions self.completer.setCompletionMode(QtWidgets.QCompleter.PopupCompletion) self.setCompleter(self.completer) # connect signals self.lineEdit().textEdited.connect(self.on_lineEdit_textEdited) self.completer.activated.connect(self.on_completer_activated) def on_lineEdit_textEdited(self, text): regex = QtCore.QRegExp(".*" + text + ".*", QtCore.Qt.CaseInsensitive, QtCore.QRegExp.RegExp) self.pFilterModel.setFilterRegExp(regex) # on selection of an item from the completer, select the corresponding item from combobox def on_completer_activated(self, text): if text: index = self.findText(text) self.setCurrentIndex(index) self.activated[str].emit(self.itemText(index)) # on model change, update the models of the filter and the completer as well def setModel(self, model): super(FilterComboBox, self).setModel(model) self.pFilterModel.setSourceModel(model) self.completer.setModel(self.pFilterModel) # on model column change, update the model column of the filter and completer as well def setModelColumn(self, column): self.completer.setCompletionColumn(column) self.pFilterModel.setFilterKeyColumn(column) super(FilterComboBox, self).setModelColumn(column)
解决方案
问题根源是QSortFilterProxyModel默认过滤模式为FilterFixedString,即使传入正则表达式,它也会把正则当成普通字符串处理,导致只有开头匹配才生效。需要明确设置过滤模式为正则匹配,并优化正则写法避免特殊字符干扰。
修改点:
- 初始化
pFilterModel时,新增两行配置:- 设置过滤角色为显示文本,确保过滤的是选项的显示内容
- 明确设置过滤模式为正则表达式匹配
- 对用户输入的文本做正则转义,避免输入
.、*等特殊字符破坏正则规则
修改后的完整代码:
class FilterComboBox(QtWidgets.QComboBox): def __init__(self, parent=None): super(FilterComboBox, self).__init__(parent) self.setFocusPolicy(QtCore.Qt.StrongFocus) self.setEditable(True) # add a filter model to filter matching items self.pFilterModel = QtCore.QSortFilterProxyModel(self) self.pFilterModel.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive) # 新增:设置过滤角色为显示文本,明确使用正则模式过滤 self.pFilterModel.setFilterRole(QtCore.Qt.DisplayRole) self.pFilterModel.setFilterMode(QtCore.QSortFilterProxyModel.FilterRegExp) # add a completer, which uses the filter model self.completer = QtWidgets.QCompleter(self.pFilterModel, self) # filter the completions self.completer.setCompletionMode(QtWidgets.QCompleter.PopupCompletion) self.setCompleter(self.completer) # connect signals self.lineEdit().textEdited.connect(self.on_lineEdit_textEdited) self.completer.activated.connect(self.on_completer_activated) def on_lineEdit_textEdited(self, text): # 转义正则特殊字符,避免用户输入干扰 escaped_text = QtCore.QRegExp.escape(text) regex = QtCore.QRegExp(f".*{escaped_text}.*", QtCore.Qt.CaseInsensitive, QtCore.QRegExp.RegExp) self.pFilterModel.setFilterRegExp(regex) # on selection of an item from the completer, select the corresponding item from combobox def on_completer_activated(self, text): if text: index = self.findText(text) self.setCurrentIndex(index) self.activated[str].emit(self.itemText(index)) # on model change, update the models of the filter and the completer as well def setModel(self, model): super(FilterComboBox, self).setModel(model) self.pFilterModel.setSourceModel(model) self.completer.setModel(self.pFilterModel) # on model column change, update the model column of the filter and completer as well def setModelColumn(self, column): self.completer.setCompletionColumn(column) self.pFilterModel.setFilterKeyColumn(column) super(FilterComboBox, self).setModelColumn(column)
内容的提问来源于stack exchange,提问作者Bikitsos
相关产品推荐
相关产品推荐

