Combobox с подсказкой вариантов в tkinter со списком на русском языке

Есть код, который выполняет поиск в списке по нажатию кнопки выпадающего списка (с подсказкой). И он работает, но если заменить данные списка lst на любые слова на русском языке, например lst=['Австралия', 'Австрия', 'Масао', 'Макао'], то подсказки перестают выдаваться. Вопрос следующий: Можно ли вводя текст в окне на русском языке получать подсказки в Combobox для выбора?

from tkinter import *
from ttkwidgets.autocomplete import AutocompleteCombobox # pip install ttkwidgets

lst = ['C', 'C++', 'Java', 'Python', 'Perl', 'PHP', 'ASP', 'JS']  
#  lst = ['Австралия', 'Австрия', 'Масао', 'Макао']

root = Tk()

# creating Combobox
combo_box = AutocompleteCombobox(root, width=30, completevalues=lst)

combo_box.pack()
root.mainloop()

Ответы (2 шт):

Автор решения: Fox Fox

У меня получился только альтернативный вариант и довольно громоздкий:

from tkinter import *
from tkinter import ttk

class AutocompleteCombobox(ttk.Combobox):

    def set_completion_list(self, completion_list):
        self._completion_list = sorted(completion_list)
        self._hits = []
        self._hit_index = 0
        self.position = 0
        self.bind('<KeyRelease>', self.handle_keyrelease)
        self['values'] = self._completion_list

    def autocomplete(self, delta=0):
        if delta:
            self.delete(self.position, END)
        else:
            self.position = len(self.get())
        _hits = []
        for item in self._completion_list:
            if item.lower().startswith(self.get().lower()):
                _hits.append(item)
        if _hits != self._hits:
            self._hit_index = 0
            self._hits = _hits
        if _hits:
            self._hit_index = (self._hit_index + delta) % len(_hits)
            self.delete(0, END)
            self.insert(0, _hits[self._hit_index])
            self.select_range(self.position, END)

    def handle_keyrelease(self, event):
        if event.keysym in ('BackSpace', 'Left', 'Right', 'Up', 'Down'):
            return
        if event.keysym == 'Return':
            self.autocomplete(1)
        else:
            self.autocomplete()

root = Tk()

lst = ['Австралия', 'Австрия', 'Масао', 'Макао', 'Germany']

combo_box = AutocompleteCombobox(root, width=30)
combo_box.set_completion_list(lst)
combo_box.pack()

root.mainloop()
→ Ссылка
Автор решения: Amgarak

Открыв оригинальный код класса AutocompleteCombobox, удалось локализовать проблему, она находится в методе:

def handle_keyrelease(self, event):
    """
    Event handler for the keyrelease event on this widget.

    :param event: Tkinter event
    """
    if event.keysym == "BackSpace":
        self.delete(self.index(tk.INSERT), tk.END)
        self.position = self.index(tk.END)
    if event.keysym == "Left":
        if self.position < self.index(tk.END):  # delete the selection
            self.delete(self.position, tk.END)
        else:
            self.position -= 1  # delete one character
            self.delete(self.position, tk.END)
    if event.keysym == "Right":
        self.position = self.index(tk.END)  # go to end (no selection)
    if event.keysym == "Return":
        self.handle_return(None)
        return
    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

Проблема в этой строчке - if len(event.keysym) == 1:

Пример:

г -> len(event.keysym) = 2 
g -> len(event.keysym) = 1

Кириллические символы проверку не проходят и автозаполнение не срабатывает.

Для решения проблемы предлагаю переписать оригинальный метод, подправив проверки:

import tkinter as tk
from ttkwidgets.autocomplete import AutocompleteCombobox 

class CastomAutocompleteCombobox(AutocompleteCombobox):
    def handle_keyrelease(self, event):
        if event.keysym == "BackSpace":
            self.delete(self.index(tk.INSERT), tk.END)
            self.position = self.index(tk.END)
        
        elif event.keysym == "Left":
            if self.position < self.index(tk.END):  
                self.delete(self.position, tk.END)
            else:
                self.position -= 1  
                self.delete(self.position, tk.END)
            
        elif event.keysym == "Right":
            self.position = self.index(tk.END)  
    
        elif event.keysym == "Return":
            self.handle_return(event)  
            return
        else:
            # Вызов автозаполнения для всех других клавиш \ можно дополнить своим условием
            self.autocomplete()

root = tk.Tk()
lst = ['Австралия', 'Австрия', 'Макао', 'Масао', 'Java', 'Python', 'Perl', 'PHP']

combo = CastomAutocompleteCombobox(root, completevalues=lst, width=30)
combo.pack(pady=10)

root.mainloop()

введите сюда описание изображения

→ Ссылка