Skip to content

Instantly share code, notes, and snippets.

@victordomingos
Forked from ian-weisser/autocomplete.py
Last active May 4, 2016 15:48
Show Gist options
  • Save victordomingos/3a2a143c573e49308aad392acff25b47 to your computer and use it in GitHub Desktop.
Save victordomingos/3a2a143c573e49308aad392acff25b47 to your computer and use it in GitHub Desktop.
Python3 tkinter text entry widget with built-in autocompletion class, with working example (revised version)
#!/usr/bin/python3
"""
tkentrycomplete.py
A tkinter widget that features autocompletion.
Created by Mitja Martini on 2008-11-29.
Converted to Python3 by Ian weisser on 2014-04-06.
Edited by Victor Domingos on 2016-04-25.
"""
import sys
import os
import tkinter
__version__ = "1.0.1"
tkinter_umlauts=['odiaeresis', 'adiaeresis', 'udiaeresis', 'Odiaeresis', 'Adiaeresis', 'Udiaeresis', 'ssharp']
class AutocompleteEntry(tkinter.Entry):
"""
Subclass of tkinter.Entry that features autocompletion.
To enable autocompletion use set_completion_list(list) to define
a list of possible strings to hit.
To cycle through hits use down and up arrow keys.
"""
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, delta=0):
"""autocomplete the Entry, delta may be 0/1/-1 to cycle through possible hits"""
if delta: # need to delete selection otherwise we would fix the current position
self.delete(self.position, tkinter.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()):
_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, tkinter.END)
self.insert(0,self._hits[self._hit_index])
self.select_range(self.position,tkinter.END)
def handle_keyrelease(self, event):
"""event handler for the keyrelease event on this widget"""
if event.keysym == "BackSpace":
if self.position < self.index(tkinter.END): # delete the selection
self.delete(self.position, tkinter.END)
else:
self.position = self.index(tkinter.END)
if event.keysym == "Left":
if self.position < self.index(tkinter.END): # delete the selection
self.delete(self.position, tkinter.END)
if event.keysym == "Right":
self.position = self.index(tkinter.END) # go to end (no selection)
if event.keysym == "Down":
self.autocomplete(1) # cycle to next hit
if event.keysym == "Up":
self.autocomplete(-1) # cycle to previous hit
# perform normal autocomplete if event is a single key or an umlaut
if len(event.keysym) == 1:
self.autocomplete()
def test(test_list):
"""Run a mini application to test the AutocompleteEntry Widget."""
root = tkinter.Tk(className=' AutocompleteEntry demo')
entry = AutocompleteEntry(root)
entry.set_completion_list(test_list)
entry.pack()
entry.focus_set()
root.mainloop()
if __name__ == '__main__':
test_list = (u'test', u'type', u'true', u'tree', u'tölz')
print("Type a 't' to test the AutocompleteEntry widget.")
print("Will use AutocompleteEntry.set_completion_list({})".format(test_list))
print("Try also the backspace key and the arrow keys.")
test(test_list)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment