Embed autocomplete tkinter in data-entry python application

1.4k views Asked by At

NOW UPDATED

  • Inserted the correct link to the Autocomplete code that works fine and
  • reduced the code of my example.

I am trying to embed autocomplete solution in a new python program. The autocomplete tkinter (https://gist.github.com/uroshekic/11078820) code is working fine on itself, but once embedded in my code I keep running into a NameError issue. (NameError: Name Entry not defined) (Line 4). While if I run the code (from the inserted link) it works fine. What am I missing?

I tried numerous different approaches.... but seem to miss the cause of the problem.

This is what I have so far:

#
import tkinter as tk
import re
class AutocompleteEntry(Entry):
    def __init__(self, autocompleteList, *args, **kwargs):
        # Listbox length
        if 'listboxLength' in kwargs:
            self.listboxLength = kwargs['listboxLength']
            del kwargs['listboxLength']
        else:
            self.listboxLength = 14
        # 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

        Entry.__init__(self, *args, **kwargs)
        self.focus()

        self.autocompleteList = autocompleteList
        self.var = self["textvariable"]
        if self.var == '':
            self.var = self["textvariable"] = StringVar()
        self.var.trace('w', self.changed)
        self.bind("<Return>", self.selection)
        self.bind("<Right>", self.selection)
        self.bind("<Up>", self.moveUp)
        self.bind("<Down>", self.moveDown)

        self.listboxUp = False

    def changed(self, name, index, mode):
        if self.var.get() == '':
            if self.listboxUp:
                self.listbox.destroy()
                self.listboxUp = False
        else:
            words = self.comparison()
            if words:
                if not self.listboxUp:
                    self.listbox = Listbox(width=self["width"], height=self.listboxLength)
                    self.listbox.bind("<Return>", self.selection)
                    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

                self.listbox.delete(0, END)
                for w in words:
                    self.listbox.insert(END,w)
            else:
                if self.listboxUp:
                    self.listbox.destroy()
                    self.listboxUp = False

    def selection(self, event):
        if self.listboxUp:
            self.var.set(self.listbox.get(ACTIVE))
            self.listbox.destroy()
            self.listboxUp = False
            self.icursor(END)

    def moveUp(self, event):
        if self.listboxUp:
            if self.listbox.curselection() == ():
                index = '0'
            else:
                index = self.listbox.curselection()[0]

            if index != '0':
                self.listbox.selection_clear(first=index)
                index = str(int(index) - 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 = '0'
            else:
                index = self.listbox.curselection()[0]

            if index != END:
                self.listbox.selection_clear(first=index)
                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) ]

class Example(tk.Frame):
    def __init__(self, parent):

        tk.Frame.__init__(self, parent)

        autocompleteList = [ 'Dora Lyons (7714)', 'Hannah Golden (6010)', 'Walker Burns (9390)', 'Dieter Pearson (6347)']

        def matches(fieldValue, acListEntry):
            pattern = re.compile(re.escape(fieldValue) + '.', re.IGNORECASE)
            return re.match(pattern, acListEntry)

        self.entry = AutocompleteEntry(autocompleteList, root, listboxLength=12, width=32, matchesFunction=matches).pack()
        self.val1 = StringVar()
        self.entry1 = tk.Entry(textvariable=val1).pack()
        self.addrow = tk.Button(self,text="Test", width=12, command=self.addrow).pack(side='left')

    def addrow(self):
        print( self.entry.get() + ", " + self.val1.get() )
        self.art.set("")

root = tk.Tk()
Example(root).pack(expand=False)
root.mainloop()

The error I get:

Traceback (most recent call last): File "D:\test6_stack.py", line 4, in class AutocompleteEntry(Entry): NameError: name 'Entry' is not defined

What is wrong with this line (line 4)

class AutocompleteEntry(Entry):

And why is it working fine when I run the code from the github code?

Thanks for your time and help. Still learning!

1

There are 1 answers

0
SchreiberLex On

Just like it says: name 'Entry' is not defined

what is 'Entry'?

Where is it defined?

I guess it's a class but i can't find it in your code nor it seems to be imported withe your imports.

(I guess you just missed to call tk.Entry ... Try to stick with the stacktrace, it says Error in Line 4, and that Entry is not defined ...)