阐明 Tkinter 自动完成条目的功能

Clarify functionality of Tkinter Autocomplete Entry

我对此有一些疑问Tkinter autocomplete entry by Mitja Martini

我已经删除了不必要的代码并留下了原作者的评论。如果您键入的速度足够慢,以便在每个字符后突出显示,则自动完成会正常工作,但是必须缓慢键入会破坏自动完成的目的,因为节省的时间很少。用户将不得不观看闪烁的亮点,或者如果他不想观看闪光灯,则只能非常缓慢地键入。

为什么我不能快速打字,而不会取消突出显示所选内容,并且光标会重新定位到所填词的末尾;结果是快速打字将字符追加到完整单词的末尾。

如何解决这个问题?

"a new hit list"是什么意思(有条件的注释掉)。我想看一个简单的例子来说明它是如何工作的 and/or 为什么我不能只删除这个条件。

"known hit list" 是什么意思(注释掉的部分)。此代码中未知命中列表的示例是什么,以便我可以看到注释行?

import tkinter as tk

class AutocompleteEntry(tk.Entry):
    def set_completion_list(self, completion_list):
        self._completion_list = completion_list
        self._hits = []
        self._hit_index = 0
        self.position = 0
        self.bind('<KeyRelease>', self.handle_keyrelease)

    def autocomplete(self):

        # 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()):
                _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) % len(self._hits)

        # perform the auto completion
        if self._hits:
            self.delete(0,tk.END)
            self.insert(0,self._hits[self._hit_index])
            self.select_range(self.position,tk.END)

    def handle_keyrelease(self, event):
        if len(event.keysym) == 1:
            self.autocomplete()

def test(test_list):
    root = tk.Tk(className=' AutocompleteEntry demo')
    root.geometry('+500+300')
    entry = AutocompleteEntry(
        root, 
        fg='white', bg='black',
        insertbackground='white', 
        font=('arial', 30))
    entry.set_completion_list(test_list)
    entry.grid()
    entry.focus_set()
    root.mainloop()

if __name__ == '__main__':
    test_list = (
        'Geronimo', 'Tecumseh', 'onomatopoeia', 
        'onerous', 'technicality', 'geriatric' )
    test(test_list)

自动完成代码的问题在于它依赖于替换突出显示的文本,因此用户必须等待文本突出显示才能键入下一个字符。发布我的问题后,我从头开始编写了自己的自动完成功能,它使用了一种不同的技术,允许用户在填写完单词后继续输入。这并没有回答上面提到的问题,但它解决了我眼前的问题,除非这段代码有一个我还没有发现的故障。这个部分答案的目的是显示一个自动填充,它不会阻止用户在填写单词后进行输入。

import tkinter as tk

chiefs = [
    'Sitting Bull', 'Geronimo', 'Tecumseh', 'Pontiac', 
    'Red Cloud', 'Crazy Horse', 'Cochise', 'Red Jacket', 
    'Red Czar', 'Red Czechoslovakian']

def match_string():
    hits = []
    got = auto.get()
    for item in chiefs:
        if item.startswith(got):
            hits.append(item)
    return hits    

def get_typed(event):
    if len(event.keysym) == 1:
        hits = match_string()
        show_hit(hits)

def show_hit(lst):
    if len(lst) == 1:
        auto.set(lst[0])
        detect_pressed.filled = True

def detect_pressed(event):    
    key = event.keysym
    if len(key) == 1 and detect_pressed.filled is True:
        pos = autofill.index(tk.INSERT)
        autofill.delete(pos, tk.END)

detect_pressed.filled = False

root = tk.Tk()

auto = tk.StringVar()

autofill = tk.Entry(
    root, 
    font=('tacoma', 30),
    bg='black',
    insertbackground='white',
    fg='white',
    textvariable=auto)
autofill.grid()
autofill.focus_set()
autofill.bind('<KeyRelease>', get_typed)
autofill.bind('<Key>', detect_pressed)

root.mainloop()