Source code for ttkwidgets.autocomplete.autocompletecombobox

"""
Authors: Mitja Martini and Russell Adams
License: "Licensed same as original by Mitja Martini or public domain, whichever is less restrictive"
Source: https://mail.python.org/pipermail/tkinter-discuss/2012-January/003041.html

Edited by RedFantom for ttk and Python 2 and 3 cross-compatibility and <Enter> binding
"""
try:
    import Tkinter as tk
    import ttk
except ImportError:
    import tkinter as tk
    from tkinter import ttk

tk_umlauts = ['odiaeresis', 'adiaeresis', 'udiaeresis', 'Odiaeresis', 'Adiaeresis', 'Udiaeresis', 'ssharp']


[docs]class AutocompleteCombobox(ttk.Combobox): """:class:`ttk.Combobox` widget that features autocompletion."""
[docs] def __init__(self, master=None, completevalues=None, **kwargs): """ Create an AutocompleteCombobox. :param master: master widget :type master: widget :param completevalues: autocompletion values :type completevalues: list :param kwargs: keyword arguments passed to the :class:`ttk.Combobox` initializer """ ttk.Combobox.__init__(self, master, values=completevalues, **kwargs) self._completion_list = completevalues if isinstance(completevalues, list): self.set_completion_list(completevalues) self._hits = [] self._hit_index = 0 self.position = 0
[docs] def set_completion_list(self, completion_list): """ Use the completion list as drop down selection menu, arrows move through menu. :param completion_list: completion values :type completion_list: list """ 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
[docs] def autocomplete(self, delta=0): """ Autocomplete the Combobox. :param delta: 0, 1 or -1: how to cycle through possible hits :type delta: int """ if delta: # need to delete selection otherwise we would fix the current position self.delete(self.position, tk.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, tk.END) self.insert(0, self._hits[self._hit_index]) self.select_range(self.position, tk.END)
[docs] 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
[docs] def handle_return(self, event): """ Function to bind to the Enter/Return key so if Enter is pressed the selection is cleared :param event: Tkinter event """ self.icursor(tk.END) self.selection_clear()