I'm trying to create a custom Tkinter Entry widget
that will convert lowercase characters to uppercase before the characters are inserted into the widget. I know there are solutions that bind key release events to a widget with a function to get the widget text and then convert to uppercase and reinsert the text. But those solutions display the lowercase character before the conversion occurs, which I prefer not to do.
I'm trying to use a custom Entry widget based on code shared by Bryan Oakley - Tkinter adding line number to text widget
This code works great for a custom Text widget
and I have used it in other applications.
Now I'm trying to use the same approach to create a custom Entry widget. Here is sample code that incorporates both a custom Text widget and custom Entry widget:
from tkinter import *
class CustomText(Text):
def __init__(self, *args, **kwargs):
Text.__init__(self, *args, **kwargs)
self._orig = self._w + "_orig"
self.tk.call("rename", self._w, self._orig)
self.tk.createcommand(self._w, self._proxy)
def _proxy(self, *args):
if args[0] == "insert" and args[1] == "insert":
args =('insert', 'insert', args[2].upper())
cmd = (self._orig,) + args
result = self.tk.call(cmd)
return result
class CustomEntry(Entry):
def __init__(self, *args, **kwargs):
Entry.__init__(self, *args, **kwargs)
self._orig = self._w + "_orig"
self.tk.call("rename", self._w, self._orig)
self.tk.createcommand(self._w, self._proxy)
def _proxy(self, *args):
if args[0] == "insert" and args[1] == "insert":
args =('insert', 'insert', args[2].upper())
cmd = (self._orig,) + args
result = self.tk.call(cmd)
return result
def get_text():
print("TEXT widget text = ", mytext.get("1.0", "end"))
print("ENTRY widget text = " ,entryvar.get())
root = Tk()
entryvar = StringVar()
root.geometry("300x300")
myframe = Frame(root, width = 300, height = 300)
Label(myframe, text="TEXT WIDGET").pack(side = TOP)
myframe.pack(side = TOP)
mytext = CustomText(myframe, width = 30, height=1, wrap="none")
mytext.pack(side = TOP)
Label(myframe, text="ENTRY WIDGET").pack(side = TOP)
myentry = CustomEntry(myframe, textvariable=entryvar, width = 30)
myentry.pack(side = TOP)
Button(myframe, text="Get Entry Widget Text", command=get_text).pack(side=TOP)
root.mainloop()
The solutions works for the CustomText
widget. As you can see the characters are converted before insertion and the result is as if the user is entering the characters with the shift key pressed.
But I get an exception when entering data into the CustomEntry
widget I get the following exception form the result = self.tk.call(cmd)
:
Traceback (most recent call last):
File "C:/Users/rhkea/AppData/Roaming/JetBrains/PyCharmCE2020.1/scratches/custom_entry_box.py", line 57, in <module>
root.mainloop()
File "C:\Users\rhkea\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1283, in mainloop
self.tk.mainloop(n)
File "C:/Users/rhkea/AppData/Roaming/JetBrains/PyCharmCE2020.1/scratches/custom_entry_box.py", line 34, in _proxy
result = self.tk.call(cmd)
_tkinter.TclError: selection isn't in widget .!frame.!customentry
Any ideas on why this might be happening?