You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于SQLite查询实现Tkinter ttk Combobox自动补全适配

整合SQLite数据加载与自动补全功能到ttk Combobox

我来帮你把自动补全功能和你现有的SQLite数据加载逻辑完美整合!下面是修改后的完整代码,我会给你拆解关键的改动点:

完整修改后的代码

from tkinter import ttk
import sqlite3

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, 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,END)
            self.insert(0,self._hits[self._hit_index])
            self.select_range(self.position,END)

    def handle_keyrelease(self, event):
        """event handler for the keyrelease event on this widget"""
        if event.keysym == "BackSpace":
            self.delete(self.index(INSERT), END)
            self.position = self.index(END)
        if event.keysym == "Left":
            if self.position < self.index(END): # delete the selection
                self.delete(self.position, END)
            else:
                self.position = self.position-1 # delete one character
                self.delete(self.position, END)
        if event.keysym == "Right":
            self.position = self.index(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 cb(x, sql_query, Var):
    global comboBox
    textfont = ("Helvetica", 14)
    # 替换普通Combobox为带自动补全的自定义类实例
    comboBox = AutocompleteCombobox(x, font=textfont, width=15, textvariable=Var)
    comboBox.pack(anchor='e', pady=5)
    update(sql_query) # 更新自动补全列表

def update(sql_query):
    lis = []
    def query():
        nonlocal sql_query
        mydb = sqlite3.connect('Assets/backend/Data.db')
        cursor = mydb.cursor()
        cursor.execute(sql_query)
        a = cursor.fetchall()
        # 提取SQL查询结果中每个元组的第一个元素,转为纯字符串列表
        lis.extend([item[0] for item in a])
        mydb.close()
    query()
    # 调用自动补全类的方法设置列表,替代直接赋值values
    comboBox.set_completion_list(lis)

# 测试示例(可根据你的界面逻辑调整)
if __name__ == '__main__':
    import tkinter as tk
    root = tk.Tk()
    var = tk.StringVar()
    # 替换为你的SQL查询语句,比如"SELECT column_name FROM your_table"
    cb(root, "SELECT name FROM test_table", var)
    root.mainloop()

关键改动说明

  • 直接复用自动补全类:原有的AutocompleteCombobox类已经实现了完整的自动补全逻辑,我们不需要修改它的核心代码,直接拿来用就行。
  • 替换Combobox实例:在cb函数里,把原来创建普通ttk.Combobox的代码改成创建AutocompleteCombobox实例,这样控件就拥有了自动补全能力。
  • 处理SQL查询结果:SQLite的fetchall()返回的是元组列表(比如[("苹果",), ("香蕉",)]),我们需要提取每个元组里的目标元素,转换成纯字符串列表,这样自动补全的匹配逻辑才能正常工作。
  • 使用自动补全设置方法:不再直接给comboBox['values']赋值,而是调用set_completion_list方法,这个方法不仅会设置下拉选项,还会自动绑定触发自动补全的键盘事件。

小建议

  • 尽量减少全局变量:我暂时保留了你原来的global comboBox写法,但实际项目中可以考虑把comboBox作为cb函数的返回值,再传入update函数,这样代码结构会更清晰规范。
  • 适配多列查询:如果你的SQL查询返回多列,只需要调整[item[0] for item in a]中的索引,选择你要用于自动补全的列即可。

内容的提问来源于stack exchange,提问作者Ahmed Hassan

火山引擎 最新活动