You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,即使传入正则表达式,它也会把正则当成普通字符串处理,导致只有开头匹配才生效。需要明确设置过滤模式为正则匹配,并优化正则写法避免特殊字符干扰。

修改点:

  1. 初始化pFilterModel时,新增两行配置:
    • 设置过滤角色为显示文本,确保过滤的是选项的显示内容
    • 明确设置过滤模式为正则表达式匹配
  2. 对用户输入的文本做正则转义,避免输入.、*等特殊字符破坏正则规则

修改后的完整代码:

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 08:25:00