1

I'm trying to create a form using ttk.widgets library. When using AutocompleteEntry, I noticed that if I don't press only one key at a time the entry is autocompleted with the first match from the first two keys I pressed (when I release the keys it autocompletes by itself), and so when typing fast this issue occurs.

import tkinter as tk
from ttkwidgets.autocomplete import AutocompleteEntry


class DfeForm(tk.Tk):

    @staticmethod
    def only_numbers(char):
        return char.isdigit()

    def character_limit(self, entry_text):
        if len(entry_text.get()) > 0:
            entry_text.set(entry_text.get()[:14])

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        padding = {'padx': 5, 'pady': 5}

        self.geometry('340x255')
        self.title("My form")
        validation = self.register(self.only_numbers)

        input1_text = tk.StringVar()
        input1_label = tk.Label(text='Entry to autocomplete:')
        input1_label.grid(row=1, column=0, sticky=tk.E, **padding)
        input1_entry = AutocompleteEntry(self, foreground='black', validate='key',
                                         validatecommand=(validation, '%S'), textvariable=input1_text,
                                         completevalues=autocompleteList)
        input1_entry.grid(row=1, column=1, **padding, sticky=tk.E)
        input1_text.trace("w", lambda *args: self.character_limit(input1_text))
        self.resizable(0, 0)


def main():
    gui = DfeForm()
    gui.mainloop()


autocompleteList = ['123555', '123666', '123777', '223555']

if __name__ == "__main__":
    main()

In this code sample, if you press '1' and then '2' (before releasing '1' key), when you release both keys the text is automatically autocompleted to the first match '123555'. So, if you try to type '123666' fast, the entry is mistakenly autocompleted to '123555'.

Herberts
  • 68
  • 5

1 Answers1

0

ttkwidgets autocomplete is done by '<KeyRelease>' and not by '<KeyPress>'. I guess the intention for this is because on some platforms the key-press event is fired continuously till release (e.g. Windows). This would lead to false results. However you could try entry.bind('<KeyPress>', entry.handle_keyrelease)

You also could implement your own validation for this event and have barrier of time that needs to be bridged to insert the exact same key. It could look like this:

class MyAutocompleteEntry(AutocompleteEntry):

    def __init__(self, master, **kwargs):
        super().__init__(master, **kwargs)
        self.last_eval = None
        self.min_delta = 50
        self.bind('<KeyPress>', self.handle_keypress)
        self.unbind('<KeyRelease>')

    def handle_keypress(self, event):
        if self.last_eval:
            if self.last_eval[0] == event.keysym:
                if event.time-self.last_eval[1] > self.min_delta:
                    self.handle_keyrelease(event)
                else:
                    return
            else:
                self.handle_keyrelease(event)
        else:
            self.handle_keyrelease(event)
        self.last_eval = (event.keysym, event.time)
Thingamabobs
  • 7,274
  • 5
  • 21
  • 54