python - Converting entry() values to upper case - python

I want to make the values I type on Entry field to be automatically converted to uppercase. I have code in here that only accepts uppercase letters to be typed in the entry using validatecommand.
from tkinter import *
root = Tk()
def text(a,b,c):
ind=int(b)
if c == '1': #insert
if not a[ind].isupper():
return False
return True
entry = Entry(root, validate="key")
entry['validatecommand'] = (entry.register(text),'%P','%i','%d')
entry.pack()
root.mainloop()

If you want to convert the entry content to uppercase instead of preventing the user to insert non uppercase letters, you can associate a StringVar to your entry and use its trace (trace_add since python 3.6) method to convert the entry content to uppercase each time the user modifies the entry.
trace takes two arguments: the mode and the callback. The mode determines when the callback is called. The modes are:
'w' ('write' for python 3.6): the callback is called when the variable is written (it's the mode I use in the code below),
'r' ('read'): the callback is called when the variable is read,
'u' ('unset'): the callback is called when the variable is deleted
For more details about the arguments of the callback, see What are the arguments to Tkinter variable trace method callbacks?
import tkinter as tk
def to_uppercase(*args):
var.set(var.get().upper())
root = tk.Tk()
var = tk.StringVar(root)
e = tk.Entry(root, textvariable=var)
e.pack()
try:
# python 3.6
var.trace_add('write', to_uppercase)
except AttributeError:
# python < 3.6
var.trace('w', to_uppercase)
root.mainloop()

You can bind to an event instead of using .trace (in python 3.x, not tested in 2.x).
The following is copied verbatum from the accepted answer (by "bevdet") to
https://bytes.com/topic/python/answers/897918-how-do-i-make-tkinter-text-entry-all-uppercase.
You can bind an event to your widget that calls a function to convert the text to upper case.
You will need to initialize a textvariable for the Entry widget. In your case, there is nothing else to take the focus, otherwise you could bind < FocusOut > to the widget. < KeyRelease > works nicely however.
from Tkinter import *
win = Tk()
def caps(event):
v.set(v.get().upper())
Label(win, text='Enter user nick:').pack(side=LEFT)
v = StringVar()
w = Entry(win, width=20, textvariable=v)
w.pack(side=LEFT)
w.bind("<KeyRelease>", caps)
mainloop()
I was able to use this method in combination with custom validation (See B. Oakley answer to
Interactively validating Entry widget content in tkinter) by placing the binding OUTSIDE the validation function, immediately after creating the Entry widget. Important: Do not put the binding inside the validation function, doing so will break the validation function (see accepted answer to Python tkInter Entry fun for explanation and a possible workaround).

Related

How do I make a button that allows me to send two variables into the same function in Tkinter?

def openCipher():
cipher = Toplevel()
cipher.title("decryptt - CIPHER")
cipherLabel = Label(cipher, text="cipher").pack()
cipherEntry = Entry(cipher, width=20, borderwidth=5) #separating pack now allows you to use get() on this
cipherEntry.pack()
cipherChoices = [
("Binary","bcipher"),
("Caesar","ccipher"),
("Hexadecimal","hcipher"),
("Atbash","acipher"),
("Letter-to-Number","lcipher")
]
cipherType = StringVar()
cipherType.set("Binary")
for text, cipherChoice in cipherChoices:
Radiobutton(cipher, text=text, variable=cipherType, value=cipherChoice).pack()
cipherButton = Button(cipher, text="Cipher", padx=10, pady=5, command=lambda:[ciphering(cipherEntry.get()), ciphering(cipherChoice.get())]).pack() #lambda allows you to pass arguments to functions
quitButton = Button(cipher, text="Exit Cipher", padx=10, pady=5, command=cipher.destroy).pack()
# This is the function that is suppose to split the input from cipherEntry into individual characters in an array.
def ciphering(entry,choice):
ciphering = Toplevel() #needed to add new label to
cipherLabeling = Label(ciphering, text = "You have inputted " + entry).pack() #couldn’t add a list to string like that, nor use get() on a list, changed to just use the string
seperatedWord = list(entry)
cipherLabeling = Label(ciphering, text = seperatedWord[2]).pack()
seperatedWordLength = len(seperatedWord)
cipherLabeling = Label(ciphering, text = seperatedWordLength).pack()
selection = Label(ciphering, text = choice).pack()
Above is part of the code I have for my ciphering app I am making in Tkinter. Took out the less important parts.
Basically, what is being created in OpenCipher() functions is an entry box that is named cipherEntry. Then there are radio buttons with different names of different ciphers and the value and variable of each radio button is the same as each other for that radio button. Then there is another button that takes whatever cipherEntry is and brings it to another window using the ciphering() function.
What I need to know is how do I also get whatever the value and/or variable of whatever radio button they have selected to that window using the same button they pressed to get to that window ( cipherButton ). Because I want to then use their selection and input to know what cipher type they want their input to be changed to. I already have the function for it sorted.
I have tried using cipherType, cipherChoice, cipherChoices but have no idea how to get them both in there. With the current code above. It works as if there was no second command. It totally disregards whatever selection I put in and the 'selection' label widget doesn't display their choice. I have also made each variable a global to see if that did anything but no luck.
I would really appreciate any assistance :)
First of all, the code should give an error because def ciphering(entry,choice) expects two positional arguments to be passed at the same time. Even after fixing that, it should give another error because cipherChoice is a string(from the list of tuples) and does not have a get attribute.
The thing to focus on here is:
command=lambda: [ciphering(cipherEntry.get()), ciphering(cipherChoice.get())]
When you say something like lambda: [func1(arg1),func1(arg2)] you are set to executing the function func1 and again func1 one after the other(so twice). What you want is to pass multiple arguments to the same function just using a normal lambda without any list, like:
command=lambda: ciphering(cipherEntry.get(), cipherType.get())
Also notice how I changed cipherChoice.get() to cipherType.get(), it is because cipherChoice is a string and also does not have a get attribute, but the value of the radiobutton should be acquired from the associated tkinter variable(StringVar) only. So you have to use cipherType.get()

How to listen to any Entry change events?

I'm writing a little program that populates values that come from an API every second into Entry components. But also I need for the user to be able to change any of the values anytime by themselves.
So what I have right now is:
from tkinter import *
root = Tk()
sv = StringVar()
def callback():
print(sv.get())
return True
e = Entry(root, textvariable=sv, validate="key", validatecommand=callback)
e.grid()
e = Entry(root)
e.grid()
root.mainloop()
This way I can activate my callback function whenever they press a key. However, I need it to happen also when the value is changed by the API ticker that changes the Entry components. I need my function to be called whenever any Entry text/value is changed on any Entry.
I used to code in Delphi and there we had an onChage event for edits, but in Python I'm a little lost.
You can use the trace method on your StringVar:
def trace_method(*args):
#do your thing...
sv.trace("w",trace_method)
If you need to pass a parameter, you can use lambda:
def trace_method(*args,parameter=None):
if parameter:
print (parameter)
sv.trace("w",lambda *args: trace_method(parameter="Something"))

With printing Entry´s text, last character is dismissed. How to fix?

I want to print the text of an Entry each time a new character is written.
By doing this with binding and a command to the widget the last character isn't printed.
I guess that the parameter 'textvariable' is getting updated after binding command had been executed. How to fix this?
from tkinter import *
master = Tk()
var = StringVar()
def execute_e(key):
print(var.get())
E = Entry(master, width=30, textvariable=var)
E.pack()
E.bind('<Key>', execute_e)
It's because the bound event function is being executed before the new key has been added.
Here's a simple workaround that uses the ability to add validation to an Entry widget (the validator accepts any key because it always returns True). The trick is that validator function is set-up to receive the value that the text will have if the change is allowed by specifying the %P when it's configuration as part of the Entry construction via the validatecommand=(validator_command, '%P').
Here's some documentation about adding validation to Entry widgets with details about how it works.
from tkinter import *
master = Tk()
var = StringVar()
def validator(new_value):
print(f'new_value: {new_value}')
return True
validator_command = master.register(validator)
E = Entry(master, width=30, textvariable=var,
validate='key',
validatecommand=(validator_command, '%P'))
E.pack()
master.mainloop()
I feel like this is a question of event handler. When a key is typed, your code first register a key press and execute the bound command execute_e. Only after it has processed this and your event handler has return will it update the entry with the character and proceed to update the tkinter variable.
Your print command therefore comes in before your variable have been updated and you print the previous version of your variable. If you try deleting a character from your entry, you'll see that you get the previous string with the character you have just erased.
The easiest way around that problem for you is probably to bind the command to the tkinter variable rather than the keybind. Do so using trace when the variable is writen like so :
var.trace('w', execute_e)
There are also some methods to manipulate the event handler and decide in which order to execute commands. root.after_idle will execute a command when the code has nothing else to do (when it has computed everything else you asked it to do). Try out this version of your code :
from tkinter import *
master = Tk()
var = StringVar()
def execute_e(*key):
def printy():
print(var.get())
master.after_idle(printy)
E = Entry(master, width=30, textvariable=var)
E.pack()
E.bind('<Key>', execute_e)
master.mainloop()

How to create entry inputs in a toplevel window

i have a problem and can't get my head around it. How to create a child window on pressing a button using tkinter in python were I can entry values like for example:
import tkinter
root = Tk()
Button(root, text='Bring up Message', command=Window).pack()
root.mainloop()
def messageWindow():
win = Toplevel()
-------->calculate------
Label(win, text=message).pack()
Button(win, text='OK', command=win.destroy).pack()
and on the message window i would like to have two entry fields were I can enter a and b and afterwards it should calc a+b and give me the result.
Thank you.
First, you should use from tkinter import * since there isn't a tkinter. preceding the module's classes used in your script.
Also, is your "Bring up Message" button supposed to call the messageWindow() function? Right now it's calling an undefined function Window. If so, you should change the Button's command and move your messageWindow() function above the line where you created the button or else it will call the function before it is defined and generate an error.
The syntax of an Entry widget in Tkinter goes as follows:
entry = Entry(root, *options)
entry.pack()
You need to pack() the entry widget after you define it. You won't be able to retrieve the input inside it if you pack() it on the same line as you define it as it will become a NoneType object.
You will need at least two Entry widgets, one to enter input a and one to enter input b.
You can also add a third Entry to print the result of the sum of a and b to, though you can use a label or just print it to the console.
entry_a = Entry(win)
entry_a.pack()
entry_b = Entry(win)
entry_b.pack()
# Optional answer entry
entry_ans = Entry(win)
entry_ans.pack()
You should then create a function (still within the messageWindow() function) that will retrieve the input from the two entries and add them, as well as another Button to call that function. I implemented some additional error-checking in the form of a try-except for when the entries are blank or contain something other than integers:
def add():
try:
a = int(entry_a.get())
b = int(entry_b.get())
ab_sum = a + b
# Optional printing to answer entry
entry_ans.delete(0, 'end')
entry_ans.insert(0, ab_sum)
except:
pass
Button(win, text="Add", command=add).pack()
"How to create entry inputs in a toplevel window"
import tkinter as tk
...
toplevel = tk.Toplevel(...)
tk.Entry(toplevel)
"How to create a child window on pressing a button..."
import tkinter as tk
...
def create_child_window(widget):
tk.Toplevel(widget)
...
root = tk.Tk()
tk.Button(root, command=lambda w = root: create_child_window(w))

Convert Tkinter textbox entry into Python Variable

(Long Question)
I'm trying to write a piece of code that will take a file path from the user using a tkinter textbox when a button is pressed. It would then convert that textbox entry to a string attached to a normal python variable so I can use that variable in a function later to use that file. The code I attached can make the label copy the text box entry, but I cannot use that variable or myvar in "normal python code". Also, in the code I tried returning myvar.get() through the function mywarWritten, but I cant set a variable equal to the mywarWritten(parameters) because that is dependent on the textbox entry that doesn't happen until the button is pressed. When the button is pressed the print function works printing the statement but it doesn't return please when the function is set equal to attempt.
(In Short)
I want to take a value, or string, from the user using a Tkinter text box, and use the entry as a normal python variable. Preferably the value in the text box would only be taken when a button is pressed.
from Tkinter import *
import Tkinter as tk
root = Tk()
root.title("MyApp")
myvar = StringVar()
def mywarWritten(*args):
print "mywarWritten",myvar.get()
please = myvar.get()
return please
#trying to make the function return the textbox entry but fails
attempt = mywarWritten()
print "plz %s" % (attempt)
#trying to just set it equal too but also fails
python_variable = myvar.get()
label = Label(root, textvariable=myvar)
label.pack()
text_entry = tk.Entry(root, textvariable=myvar)
button1 = tk.Button(root, text="Back to Home", command=lambda: mywarWritten())
button1.pack()
text_entry.pack()
#trying attempt and pythonvariable in "normal python code"
print attempt
print pythonvariable
root.mainloop()
Thanks for the help in advance.
You seem to have a few misunderstandings about scope, imports, references, and functions. myvar is already accessible, and all you have to do to access it is get() it. Don't import the same module multiple times, and try to avoid from x import *. Returning a value to a button doesn't make any sense and has no effect. Every line of code not in a function or class is executed immediately, so attempt = mywarWritten() and all of the other several times you did that outside a function will get the value of that StringVar as soon as the program runs, before there's anything in it. And lambda: func() is just func.
import Tkinter as tk
root = tk.Tk()
root.title("MyApp")
myvar = tk.StringVar()
def mywarWritten(*args):
print "mywarWritten", myvar.get()
label = tk.Label(root, textvariable=myvar)
label.pack()
text_entry = tk.Entry(root, textvariable=myvar)
button1 = tk.Button(root, text="Back to Home", command=mywarWritten)
button1.pack()
text_entry.pack()
root.mainloop()
Any time you want to access the contents of that entry widget, just do myvar.get() and there it will be.
You also have mywarWritten instead of my_var_written, with a v for var.
Overall, I very highly recommend you read the official Python tutorial (and use Python 3, because it's better than Python 2).

Categories