Combobox怎么实现模糊匹配?
下拉列表中有多个选项,怎么实现输入部分字符后自动将最接近的选项调到下拉列表的第一位?或者通过其他方法达到类似的功能也行
例如我输入Pn7,自动将Pn789调到下拉列表的第一位
你说的应该是一个事件,内容改变事件,具体代码百度下。 本帖最后由 qq1151985918 于 2021-1-8 09:05 编辑
我从网上给你找了个,用的是PyQt5
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QSortFilterProxyModel
from PyQt5.QtWidgets import QCompleter, QComboBox
class ExtendedComboBox(QComboBox):
def __init__(self, parent=None):
super(ExtendedComboBox, self).__init__(parent)
self.setFocusPolicy(Qt.StrongFocus)
self.setEditable(True)
# add a filter model to filter matching items
self.pFilterModel = QSortFilterProxyModel(self)
self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
self.pFilterModel.setSourceModel(self.model())
# add a completer, which uses the filter model
self.completer = QCompleter(self.pFilterModel, self)
# always show all (filtered) completions
self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
self.setCompleter(self.completer)
# connect signals
self.lineEdit().textEdited.connect(self.pFilterModel.setFilterFixedString)
self.completer.activated.connect(self.on_completer_activated)
# 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.emit(self.itemText(index))
# on model change, update the models of the filter and completer as well
def setModel(self, model):
super(ExtendedComboBox, 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(ExtendedComboBox, self).setModelColumn(column)
if __name__ == "__main__":
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QStringListModel
app = QApplication(sys.argv)
string_list = ['语文 Chinese', '数学 Mathematics', '英语 English']
combo = ExtendedComboBox()
# either fill the standard model of the combobox
combo.addItems(string_list)
# or use another model
#combo.setModel(QStringListModel(string_list))
combo.resize(300, 40)
combo.show()
sys.exit(app.exec_())
原文见链接pyQt5 QcomboBox 下拉选项模糊搜索
https://www.cnblogs.com/6min/articles/10751959.html z5560636 发表于 2021-1-8 08:53
你说的应该是一个事件,内容改变事件,具体代码百度下。
搜了一下这方面的资料很少,沒找到tkinter的combobox的相关操作... qq1151985918 发表于 2021-1-8 09:04
我从网上给你找了个,用的是PyQt5
原文见链接pyQt5 QcomboBox 下拉选项模糊搜索
感谢!~~
效果OK,还不会pyqt,我看看先 本帖最后由 qq1151985918 于 2021-1-8 09:28 编辑
lengyue869 发表于 2021-1-8 09:11
搜了一下这方面的资料很少,沒找到tkinter的combobox的相关操作...
楼主你贴的图片是你自己写的效果图吗?有没有代码看一下?你怎么实现的输入文字显示下拉列表内容? qq1151985918 发表于 2021-1-8 09:23
楼主你贴的图片是你自己写的效果图吗?有没有代码看一下?你怎么实现的输入文字显示下拉列表内容?
from tkinter import ttk
import tkinter as tk
root = tk.Tk()
root.geometry('850x400+300+100')
comb1Text = tk.StringVar()
comb2Text = tk.StringVar()
etyText = tk.StringVar()
def com1_select(*args):
print(comb1.get())
return comb1.get()
def com2_select(*args):
print(comb2.get())
return comb2.get()
# PN下拉框
comb1 = ttk.Combobox(root, textvariable=comb1Text, width=70)
comb1["values"] = ['Pn123', 'Pn456', 'Pn789']
comb1.bind("<<ComboboxSelected>>", com1_select)
pn = com1_select()
# user configuration下拉框
comb2 = ttk.Combobox(root, textvariable=comb2Text, width=70)
comb2["values"] = ['A', 'B', 'C']
comb2.bind("<<ComboboxSelected>>", com2_select)
user = com2_select()
tk.Label(root, text='BOM PN & Ver:').grid(row=0, column=0)
tk.Label(root, text='').grid(row=1, column=0)
tk.Label(root, text='User Configuration:').grid(row=2, column=0)
comb1.grid(row=0, column=1)
comb2.grid(row=2, column=1)
root.mainloop()
lengyue869 发表于 2021-1-8 09:38
原来你没能做到输入文字显示下拉列表内容,我说嘛,如果做到这个要求了应该就能做到模糊匹配了,因为我直觉感觉如果Combobox如果有一个textchange事件或者能够实现的话,就能够做到模糊匹配了 qq1151985918 发表于 2021-1-8 09:48
原来你没能做到输入文字显示下拉列表内容,我说嘛,如果做到这个要求了应该就能做到模糊匹配了,因为我直 ...
额,我再找找combobox的教程看看 找到了一个,哈哈
import tkinter
from tkinter import ttk
class AutocompleteCombobox(ttk.Combobox):
def set_completion_list(self, completion_list):
"""Use our completion list as our drop down selection menu, arrows move through menu."""
self._completion_list = sorted(completion_list, key=str.lower) # Work with a sorted list
self._hits = []
self._hit_index = 0
self.position = 0
self.bind('<KeyRelease>', self.handle_keyrelease)
self['values'] = self._completion_list# Setup our popup menu
def autocomplete(self, delta=0):
"""autocomplete the Combobox, delta may be 0/1/-1 to cycle through possible hits"""
if delta: # need to delete selection otherwise we would fix the current position
self.delete(self.position, tkinter.END)
else: # set position to end so selection starts where textentry ended
self.position = len(self.get())
# collect hits
_hits = []
for element in self._completion_list:
if element.lower().startswith(self.get().lower()): # Match case insensitively
_hits.append(element)
# if we have a new hit list, keep this in mind
if _hits != self._hits:
self._hit_index = 0
self._hits=_hits
# only allow cycling if we are in a known hit list
if _hits == self._hits and self._hits:
self._hit_index = (self._hit_index + delta) % len(self._hits)
# now finally perform the auto completion
if self._hits:
self.delete(0,tkinter.END)
self.insert(0,self._hits)
self.select_range(self.position,tkinter.END)
def handle_keyrelease(self, event):
"""event handler for the keyrelease event on this widget"""
if event.keysym == "BackSpace":
self.delete(self.index(tkinter.INSERT), tkinter.END)
self.position = self.index(tkinter.END)
if event.keysym == "Left":
if self.position < self.index(tkinter.END): # delete the selection
self.delete(self.position, tkinter.END)
else:
self.position = self.position-1 # delete one character
self.delete(self.position, tkinter.END)
if event.keysym == "Right":
self.position = self.index(tkinter.END) # go to end (no selection)
if len(event.keysym) == 1:
self.autocomplete()
# No need for up/down, we'll jump to the popup
# list at the position of the autocompletion
def test(test_list):
"""Run a mini application to test the AutocompleteEntry Widget."""
root = tkinter.Tk(className='AutocompleteCombobox')
combo = AutocompleteCombobox(root)
combo.set_completion_list(test_list)
combo.pack()
combo.focus_set()
# I used a tiling WM with no controls, added a shortcut to quit
root.bind('<Control-Q>', lambda event=None: root.destroy())
root.bind('<Control-q>', lambda event=None: root.destroy())
root.mainloop()
if __name__ == '__main__':
test_list = ('apple', 'banana', 'Cranberry', 'dogwood', 'alpha', 'Acorn', 'Anise', 'Strawberry' )
test(test_list) lengyue869 发表于 2021-1-8 10:03
找到了一个,哈哈
我试了下,这个不应该算作模糊搜索,应该算输入提示,比如 要搜索banana,
模糊搜索应该是输入ana nan都可以
不过应该可以 在这个基础上修改了 qq1151985918 发表于 2021-1-8 10:12
我试了下,这个不应该算作模糊搜索,应该算输入提示,比如 要搜索banana,
模糊搜索应该是输入ana ...
是的,不过看起来好像很复杂的样子.... qq1151985918 发表于 2021-1-8 10:12
我试了下,这个不应该算作模糊搜索,应该算输入提示,比如 要搜索banana,
模糊搜索应该是输入ana ...
还是PyQt5那个效果好一些,要是能移植到tkinter上来就好了{:5_109:} lengyue869 发表于 2021-1-8 10:32
还是PyQt5那个效果好一些,要是能移植到tkinter上来就好了
我先研究研究能不能把你刚刚搜索到的修改一下 qq1151985918 发表于 2021-1-8 10:50
我先研究研究能不能把你刚刚搜索到的修改一下
那真是太感谢了!~{:5_108:}{:5_108:}{:5_108:} lengyue869 发表于 2021-1-8 10:54
那真是太感谢了!~
只能说是尝试 qq1151985918 发表于 2021-1-8 11:07
只能说是尝试
那也感谢{:5_109:} lengyue869 发表于 2021-1-8 10:54
那真是太感谢了!~
抱歉,我改了半天,只能实现得很不完善,我想或许我得加入re来改,实在是太没有必要,因为这还得配合Combobox的其他用法和事件相配合,我功夫还不够...暂时改不成了,或许论坛的大神们出手可以。 qq1151985918 发表于 2021-1-8 12:13
抱歉,我改了半天,只能实现得很不完善,我想或许我得加入re来改,实在是太没有必要,因为这还得配合Comb ...
it's ok,不行的话就用pyqt的布局,我抽时间学下pyqt{:5_110:} lengyue869 发表于 2021-1-8 12:18
it's ok,不行的话就用pyqt的布局,我抽时间学下pyqt
你先研究着,我也还在想修改的办法,如果改成功了会告诉你
页:
[1]
2