piccoloser
piccoloser

Reputation: 281

How to restrict Text widget input to certain characters with Tkinter?

I have a Text widget (my_text) in my program that should only accept certain characters. If the user enters a character that isn't defined in a dictionary (ACCEPTED), the program should either ignore the input entirely or, at the very least, remove the character right after it's been entered. Otherwise, the program should output the corresponding value into my_text2.

I'm doing my best to also ensure that my program accounts for text entered before the end of the text content. For example, say a user goes back and inserts text in the middle of a sentence; this program should still function as expected. This is an example of the logic I'm working with:

import tkinter as tk


# For this example, I'm converting the output from
# a QWERTY keyboard to the output of a Dvorak keyboard.
ACCEPTED = {
    "q": "'",
    "w": ",",
    "e": ".",
    "r": "p",
    "t": "y",
    "y": "f",
    # ...
}


def handle_input(s):
    my_text2.configure(state = tk.NORMAL)

    if s.char in set(ACCEPTED):
        my_text2.insert(
            my_text.index(tk.INSERT),
            ACCEPTED[s.char]
        )

    elif s.keysym.lower() in {"backspace", "delete"}:
        my_text2.delete(
            my_text.index(tk.INSERT)
            + "-1c" * (s.keysym.lower() == "backspace")
        )

    # This is the part I'm missing.
    else:
        pass

    my_text2.configure(state = tk.DISABLED)


root = tk.Tk()
root.geometry("648x163+10+10")

my_text = tk.Text(
    root,
    width = 40,
    height = 10,
)
my_text.bind("<Key>", handle_input)

my_text2 = tk.Text(
    root,
    width = 40,
    height = 10,
    state = tk.DISABLED,
)

my_text.grid(column = 0, row = 0)
my_text2.grid(column = 1, row = 0)

root.mainloop()

These two Text widgets must remain synced for my program to function properly.

So far, I've tried my_text.delete(tk.INSERT), my_text.delete(tk.CURRENT), and a "-1c" variant of both. I'm still fairly new to Tkinter, so I'm not sure what's going on. It looks to me like the text isn't actually entered into my_text until after handle_input() runs, meaning that there won't be anything to delete. When I enter a character that isn't defined in ACCEPTED, it still shows up in my_text, which desyncs the two Text widgets.

Everywhere where I've found a similar issue, the problem at hand doesn't account for text before tk.END, but I'm trying to match up these two Text widgets perfectly, so tk.END won't work for me.

Upvotes: 0

Views: 1736

Answers (1)

TheLizzard
TheLizzard

Reputation: 7680

Returning "break" from a function that is called from an event, will stop the event. That means that tkinter's widget will never get the event.

Upvotes: 1

Related Questions