certflow.widgets.quick_search 源代码
"""可复用快查框控件(公共 widgets 模块)。
从 ``import_dialog.order_quick_search`` 与 ``FilterBar`` 内联快查框抽取为独立控件,
统一「editable + completer 模糊匹配」交互(§1.7 收益:导入快查框可复用到已导入库查询)。
与快查逻辑 :class:`certflow.widgets.quick_search_preset.QuickSearchPresetMixin` 同处
``widgets/`` 包,做到「控件 + 逻辑」语义聚拢。
设计要点:
- **数据源无关**:仅负责「去重候选项 → 模糊匹配 → 选中转发」交互,候选数据由宿主提供。
- **双信号(动态搜索模式切换)**:
- ``typing``:用户在输入框键入(真实输入、非程序赋值)时发出,携带当前文本。
驱动「模糊匹配模式」——下拉由 completer 做模糊初步筛选,宿主再做防抖的初步数据筛
选。程序化的 ``set_items`` / ``setCurrentText`` 不会触发,避免噪声。
- ``activated``:用户点击/回车**选中某个具体条目**时发出(对齐
``QComboBox.textActivated`` 的 QString 重载,避开 ``activated(int)`` 默认重载收到索引
的坑),驱动「精确匹配模式」——按字段逐段精确回填并查询。
"""
from __future__ import annotations
from PySide6.QtCore import Qt, Signal
from PySide6.QtWidgets import QComboBox, QCompleter
[文档]
class QuickSearch(QComboBox):
"""可编辑模糊匹配快查框。"""
# 模糊模式:用户正在输入(候选下拉已做模糊匹配)
typing = Signal(str)
# 精确模式:用户选中了某个具体候选条目
activated = Signal(str)
def __init__(
self,
parent=None,
*,
placeholder: str = "",
min_width: int = 260,
filter_mode=Qt.MatchContains,
) -> None:
super().__init__(parent)
self.setEditable(True)
self.setMinimumWidth(min_width)
if placeholder:
self.setPlaceholderText(placeholder)
self._filter_mode = filter_mode
# 程序化改文本(填充候选项 / 清空输入)时不向宿主发 typing 信号
self._suppress_typing = False
self.textActivated.connect(self._on_activated)
self.currentTextChanged.connect(self._on_text_changed)
# 回车确认:将当前输入作为一次显式查询请求(避免「边输入边查询」)。
# 与选中下拉候选(textActivated→activated)走同一确认路径;若文本恰好是候选
# 项则由 textActivated 负责发出,避免重复查询。
self.lineEdit().returnPressed.connect(self._on_return_pressed)
def _on_activated(self, text: str) -> None:
self.activated.emit(text)
def _on_text_changed(self, text: str) -> None:
# 仅对「真实用户输入」发模糊信号;选中条目时 textActivated 会随后触发精确模式
if self._suppress_typing:
return
self.typing.emit(text or "")
def _on_return_pressed(self) -> None:
text = self.currentText()
# 当前文本正好是某个候选项时,textActivated 已会发出 activated,跳过以免重复查询
if self.findText(text) != -1:
return
self.activated.emit(text)
[文档]
def set_items(self, items: list[str]) -> None:
"""填充候选项(editable + completer 模糊匹配),并清空当前输入。"""
self._suppress_typing = True
self.blockSignals(True)
self.clear()
self.addItems(items)
self.setCurrentText("")
self.blockSignals(False)
self._suppress_typing = False
completer = QCompleter(items)
completer.setCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
completer.setFilterMode(self._filter_mode)
self.setCompleter(completer)