Forked from ricardj/tkinter-autocomplete-listbox.py
Last active
December 20, 2022 04:05
-
-
Save samuelkazeem/f3e7780de569f0cba5fd3eab469749a4 to your computer and use it in GitHub Desktop.
Tkinter - Autocomplete Entry Field
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| changes made: | |
| make widgets parent explicitly declared | |
| Use either with root window or Toplevel | |
| Bind Return key to selection method | |
| """ | |
| #from tkinter import * | |
| import tkinter as tk | |
| import re | |
| class AutocompleteEntry(tk.Entry): | |
| def __init__(self, autocompleteList, *args, **kwargs): | |
| self.listboxLength = 0 | |
| self.parent = args[0] | |
| # Custom matches function | |
| if 'matchesFunction' in kwargs: | |
| self.matchesFunction = kwargs['matchesFunction'] | |
| del kwargs['matchesFunction'] | |
| else: | |
| def matches(fieldValue, acListEntry): | |
| pattern = re.compile( | |
| '.*' + re.escape(fieldValue) + '.*', re.IGNORECASE) | |
| return re.match(pattern, acListEntry) | |
| self.matchesFunction = matches | |
| # Custom return function | |
| if 'returnFunction' in kwargs: | |
| self.returnFunction = kwargs['returnFunction'] | |
| del kwargs['returnFunction'] | |
| else: | |
| def selectedValue(value): | |
| print(value) | |
| self.returnFunction = selectedValue | |
| tk.Entry.__init__(self, *args, **kwargs) | |
| #super().__init__(*args, **kwargs) | |
| self.focus() | |
| self.autocompleteList = autocompleteList | |
| self.var = self["textvariable"] | |
| if self.var == '': | |
| self.var = self["textvariable"] = tk.StringVar() | |
| self.var.trace('w', self.changed) | |
| self.bind("<Right>", self.selection) | |
| self.bind("<Up>", self.moveUp) | |
| self.bind("<Down>", self.moveDown) | |
| self.bind("<Return>", self.selection) | |
| self.bind("<Escape>", self.deleteListbox) | |
| self.listboxUp = False | |
| def deleteListbox(self, event=None): | |
| if self.listboxUp: | |
| self.listbox.destroy() | |
| self.listboxUp = False | |
| def select(self, event=None): | |
| if self.listboxUp: | |
| index = self.listbox.curselection()[0] | |
| value = self.listbox.get(tk.ACTIVE) | |
| self.listbox.destroy() | |
| self.listboxUp = False | |
| self.delete(0, tk.END) | |
| self.insert(tk.END, value) | |
| self.returnFunction(value) | |
| def changed(self, name, index, mode): | |
| if self.var.get() == '': | |
| self.deleteListbox() | |
| else: | |
| words = self.comparison() | |
| if words: | |
| if not self.listboxUp: | |
| self.listboxLength = len(words) | |
| self.listbox = tk.Listbox(self.parent, | |
| width=self["width"], height=self.listboxLength) | |
| self.listbox.bind("<Button-1>", self.selection) | |
| self.listbox.bind("<Right>", self.selection) | |
| self.listbox.place( | |
| x=self.winfo_x(), y=self.winfo_y() + self.winfo_height()) | |
| self.listboxUp = True | |
| else: | |
| self.listboxLength = len(words) | |
| self.listbox.config(height=self.listboxLength) | |
| self.listbox.delete(0, tk.END) | |
| for w in words: | |
| self.listbox.insert(tk.END, w) | |
| else: | |
| self.deleteListbox() | |
| def selection(self, event): | |
| if self.listboxUp: | |
| self.var.set(self.listbox.get(tk.ACTIVE)) | |
| self.listbox.destroy() | |
| self.listboxUp = False | |
| self.icursor(tk.END) | |
| def moveUp(self, event): | |
| if self.listboxUp: | |
| if self.listbox.curselection() == (): | |
| index = '0' | |
| else: | |
| index = self.listbox.curselection()[0] | |
| self.listbox.selection_clear(first=index) | |
| index = str(int(index) - 1) | |
| if int(index) == -1: | |
| index = str(self.listboxLength-1) | |
| self.listbox.see(index) # Scroll! | |
| self.listbox.selection_set(first=index) | |
| self.listbox.activate(index) | |
| def moveDown(self, event): | |
| if self.listboxUp: | |
| if self.listbox.curselection() == (): | |
| index = '-1' | |
| else: | |
| index = self.listbox.curselection()[0] | |
| if index != tk.END: | |
| self.listbox.selection_clear(first=index) | |
| if int(index) == self.listboxLength-1: | |
| index = "0" | |
| else: | |
| index = str(int(index)+1) | |
| self.listbox.see(index) # Scroll! | |
| self.listbox.selection_set(first=index) | |
| self.listbox.activate(index) | |
| def comparison(self): | |
| return [w for w in self.autocompleteList if self.matchesFunction(self.var.get(), w)] | |
| if __name__ == '__main__': | |
| autocompleteList = ['Dora Lyons (7714)', 'Hannah Golden (6010)', 'Walker Burns (9390)', 'Dieter Pearson (6347)', 'Allen Sullivan (9781)', 'Warren Sullivan (3094)', 'Genevieve Mayo (8427)', 'Igor Conner (4740)', 'Ulysses Shepherd (8116)', 'Imogene Bullock (6736)', 'Dominique Sanchez (949)', 'Sean Robinson (3784)', 'Diana Greer (2385)', 'Arsenio Conrad (2891)', 'Sophia Rowland (5713)', 'Garrett Lindsay (5760)', 'Lacy Henry (4350)', 'Tanek Conley (9054)', 'Octavia Michael (5040)', 'Kimberly Chan (1989)', 'Melodie Wooten (7753)', 'Winter Beard (3896)', 'Callum Schultz (7762)', 'Prescott Silva (3736)', 'Adena Crane (6684)', 'Ocean Schroeder (2354)', 'Aspen Blevins (8588)', 'Allegra Gould (7323)', 'Penelope Aguirre (7639)', 'Deanna Norman (1963)', 'Herman Mcintosh (1776)', 'August Hansen (547)', 'Oscar Sanford (2333)', 'Guy Vincent (1656)', 'Indigo Frye (3236)', 'Angelica Vargas (1697)', 'Bevis Blair (4354)', 'Trevor Wilkinson (7067)', 'Kameko Lloyd (2660)', 'Giselle Gaines (9103)', 'Phyllis Bowers (6661)', 'Patrick Rowe (2615)', 'Cheyenne Manning (1743)', 'Jolie Carney (6741)', 'Joel Faulkner (6224)', 'Anika Bennett (9298)', 'Clayton Cherry (3687)', 'Shellie Stevenson (6100)', 'Marah Odonnell (3115)', | |
| 'Quintessa Wallace (5241)', 'Jayme Ramsey (8337)', 'Kyle Collier (8284)', 'Jameson Doyle (9258)', 'Rigel Blake (2124)', 'Joan Smith (3633)', 'Autumn Osborne (5180)', 'Renee Randolph (3100)', 'Fallon England (6976)', 'Fallon Jefferson (6807)', 'Kevyn Koch (9429)', 'Paki Mckay (504)', 'Connor Pitts (1966)', 'Rebecca Coffey (4975)', 'Jordan Morrow (1772)', 'Teegan Snider (5808)', 'Tatyana Cunningham (7691)', 'Owen Holloway (6814)', 'Desiree Delaney (272)', 'Armand Snider (8511)', 'Wallace Molina (4302)', 'Amela Walker (1637)', 'Denton Tillman (201)', 'Bruno Acevedo (7684)', 'Slade Hebert (5945)', 'Elmo Watkins (9282)', 'Oleg Copeland (8013)', 'Vladimir Taylor (3846)', 'Sierra Coffey (7052)', 'Holmes Scott (8907)', 'Evelyn Charles (8528)', 'Steel Cooke (5173)', 'Roth Barrett (7977)', 'Justina Slater (3865)', 'Mara Andrews (3113)', 'Ulla Skinner (9342)', 'Reece Lawrence (6074)', 'Violet Clay (6516)', 'Ainsley Mcintyre (6610)', 'Chanda Pugh (9853)', 'Brody Rosales (2662)', 'Serena Rivas (7156)', 'Henry Lang (4439)', 'Clark Olson (636)', 'Tashya Cotton (5795)', 'Kim Matthews (2774)', 'Leilani Good (5360)', 'Deirdre Lindsey (5829)', 'Macy Fields (268)', 'Daniel Parrish (1166)', 'Talon Winters (8469)'] | |
| def matches(fieldValue, acListEntry): | |
| pattern = re.compile(re.escape(fieldValue) + '.*', re.IGNORECASE) | |
| return re.match(pattern, acListEntry) | |
| root = tk.Tk() | |
| topLevel = tk.Toplevel() | |
| topLevel.title('TopLevel') | |
| #pass either root or toplevel as the second argument to use as entry's parent widget | |
| entry = AutocompleteEntry( | |
| autocompleteList, topLevel, width=32, matchesFunction=matches) | |
| entry.grid(row=0, column=0) | |
| tk.Button(topLevel, text='Python').grid(column=0) | |
| tk.Button(topLevel, text='Tkinter').grid(column=0) | |
| tk.Button(topLevel, text='Regular Expressions').grid(column=0) | |
| tk.Button(topLevel, text='Fixed bugs').grid(column=0) | |
| tk.Button(topLevel, text='New features').grid(column=0) | |
| tk.Button(topLevel, text='Check code comments').grid(column=0) | |
| root.mainloop() |
Author
@FelRF your question is not really clear
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Can you please tell me wich line of code have the solution for toplevel and other windows use just for understand it better? Plus, congratz for the great job!