【问题标题】:Clarify functionality of Tkinter Autocomplete Entry阐明 Tkinter 自动完成条目的功能
【发布时间】:2020-02-14 03:13:07
【问题描述】:

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

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

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

如何解决这个问题?

什么是“新的命中列表”(有条件的注释掉)。我想看一个简单的例子来说明它是如何工作的和/或为什么我不能只删除这个条件。

“已知命中列表”是什么意思(注释掉的部分)。此代码中的未知命中列表的示例是什么,所以我可以看到注释行在起作用?

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)

【问题讨论】:

  • 请修正代码中的缩进。如所写,代码不会运行并且是模棱两可的。
  • 您是否考虑过尝试直接联系此代码的作者?
  • @BryanOakley 我应该问问代码的作者。在发布了这个问题后,我意识到我已经在这个自动完成功能上玩了一年多了,并且从未尝试过编写自己的自动完成功能。我的目标是不使用突出显示,看起来这解决了问题。

标签: python tkinter autocomplete


【解决方案1】:

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

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()

【讨论】:

  • 不错!这在 Python 3.8.1 中完美运行。
猜你喜欢
  • 2016-08-18
  • 2022-08-15
  • 2013-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-21
  • 2011-03-07
相关资源
最近更新 更多