Tkinter 文本自动填充

Tkinter Text Autofill

我正在尝试使用 tkinter 为 python 制作一个简单且个性化的 IDE。我以前看过它,并且将所有形式的语法突出显示到内置终端,但没有自动填充的问题。我知道您可以使用许多方法在条目中自动填充,但是在搜索带有文本条目的自动填充后,我找不到任何东西。如果我能得到一些帮助,那就太好了!我正在寻找类似于此处所见的内容。

类似思路代码:

from ttkwidgets.autocomplete import AutocompleteEntry
from tkinter import *

countries = [
        'Antigua and Barbuda', 'Bahamas','Barbados','Belize', 'Canada',
        'Costa Rica ', 'Cuba', 'Dominica', 'Dominican Republic', 'El Salvador ',
        'Grenada', 'Guatemala ', 'Haiti', 'Honduras ', 'Jamaica', 'Mexico',
        'Nicaragua', 'Saint Kitts and Nevis', 'Panama ', 'Saint Lucia', 
        'Saint Vincent and the Grenadines', 'Trinidad and Tobago', 'United States of America'
        ]

ws = Tk()
ws.title('PythonGuides')
ws.geometry('400x300')
ws.config(bg='#f25252')

frame = Frame(ws, bg='#f25252')
frame.pack(expand=True)

Label(
    frame, 
    bg='#f25252',
    font = ('Times',21),
    text='Countries in North America '
    ).pack()

entry = AutocompleteEntry(
    frame, 
    width=30, 
    font=('Times', 18),
    completevalues=countries
    )
entry.pack()

ws.mainloop()

Link 到 AutocompleteEntry

的源代码

对于基本的自动完成功能,基本算法相当简单:

  • 拦截键释放(在 tkinter 自动插入键入的文本后发生)
  • 获取光标前的单词并调用回调以查找可能的匹配项
  • 添加第一个可能的匹配项,以及 select 添加的部分以便将来的按键将替换它

您还可以为 Tab 键添加一个绑定,它将查看是否有可见的自动完成文本,并将光标移动到末尾。

这是一个非常hacked-together的示例来说明原理,尽管它缺乏任何防弹、优化或边缘情况的处理,例如退格、在单词中间键入、选择替代替换、等等

明确一点:这不是实现自动完成的最佳方式,它只是说明概念。

import tkinter as tk

class AutocompleteText(tk.Text):
    def __init__(self, *args, **kwargs):
        self.callback = kwargs.pop("autocomplete", None)
        super().__init__(*args, **kwargs)

        # bind on key release, which will happen after tkinter
        # inserts the typed character
        self.bind("<Any-KeyRelease>", self._autocomplete)

        # special handling for tab, which needs to happen on the
        # key _press_
        self.bind("<Tab>", self._handle_tab)

    def _handle_tab(self, event):
        # see if any text has the "autocomplete" tag
        tag_ranges= self.tag_ranges("autocomplete")
        if tag_ranges:
            # move the insertion cursor to the end of
            # the selected text, and then remove the "sel"
            # and "autocomplete" tags
            self.mark_set("insert", tag_ranges[1])
            self.tag_remove("sel", "1.0", "end")
            self.tag_remove("autocomplete", "1.0", "end")

            # prevent the default behavior of inserting a literal tab
            return "break"

    def _autocomplete(self, event):
        if event.char and self.callback:
            # get word preceeding the insertion cursor
            word = self.get("insert-1c wordstart", "insert-1c wordend")

            # pass word to callback to get possible matches
            matches = self.callback(word)

            if matches:
                # autocomplete on the first match
                remainder = matches[0][len(word):]

                # remember the current insertion cursor
                insert = self.index("insert")

                # insert at the insertion cursor the remainder of
                # the matched word, and apply the tag "sel" so that
                # it is selected. Also, add the "autocomplete" text
                # which will make it easier to find later.
                self.insert(insert, remainder, ("sel", "autocomplete"))

                # move the cursor back to the saved position
                self.mark_set("insert", insert)


def get_matches(word):
    # For illustrative purposes, pull possible matches from 
    # what has already been typed. You could just as easily 
    # return a list of pre-defined keywords.
    words = text.get("1.0", "end-1c").split()
    matches = [x for x in words if x.startswith(word)]
    return matches

root = tk.Tk()
text = AutocompleteText(root, autocomplete=get_matches)
text.pack(fill="both", expand=True)

root.mainloop()